wpa_supplicant: Update to 07-Jul-2012 TOT
commit a5ed45586c63ffd8f9d2b44e27c251d7bacbeaf4
Author: Jouni Malinen <j@w1.fi>
Date: Sat Jul 7 13:01:45 2012 +0300
WPS SSDP: Fix socket leaks on error paths
Change-Id: I0864aac7fc88fa2a60f5cca7d524b94363410c85
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index 47f2423..9fc05f7 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,112 @@
ChangeLog for hostapd
+2012-05-10 - v1.0
+ * Add channel selection support in hostapd. See hostapd.conf.
+ * Add support for IEEE 802.11v Time Advertisement mechanism with UTC
+ TSF offset. See hostapd.conf for config info.
+ * Delay STA entry removal until Deauth/Disassoc TX status in AP mode.
+ This allows the driver to use PS buffering of Deauthentication and
+ Disassociation frames when the STA is in power save sleep. Only
+ available with drivers that provide TX status events for Deauth/
+ Disassoc frames (nl80211).
+ * Allow PMKSA caching to be disabled on the Authenticator. See
+ hostap.conf config parameter disable_pmksa_caching.
+ * atheros: Add support for IEEE 802.11w configuration.
+ * bsd: Add support for setting HT values in IFM_MMASK.
+ * Allow client isolation to be configured with ap_isolate. Client
+ isolation can be used to prevent low-level bridging of frames
+ between associated stations in the BSS. By default, this bridging
+ is allowed.
+ * Allow coexistance of HT BSSes with WEP/TKIP BSSes.
+ * Add require_ht config parameter, which can be used to configure
+ hostapd to reject association with any station that does not support
+ HT PHY.
+ * Add support for writing debug log to a file using "-f" option. Also
+ add relog CLI command to re-open the log file.
+ * Add bridge handling for WDS STA interfaces. By default they are
+ added to the configured bridge of the AP interface (if present),
+ but the user can also specify a separate bridge using cli command
+ wds_bridge.
+ * hostapd_cli:
+ - Add wds_bridge command for specifying bridge for WDS STA
+ interfaces.
+ - Add relog command for reopening log file.
+ - Send AP-STA-DISCONNECTED event when an AP disconnects a station
+ due to inactivity.
+ - Add wps_config ctrl_interface command for configuring AP. This
+ command can be used to configure the AP using the internal WPS
+ registrar. It works in the same way as new AP settings received
+ from an ER.
+ - Many WPS/WPS ER commands - see WPS/WPS ER sections for details.
+ - Add command get version, that returns hostapd version string.
+ * WNM: Add BSS Transition Management Request for ESS Disassoc Imminent.
+ Use hostapd_cli ess_disassoc (STA addr) (URL) to send the
+ notification to the STA.
+ * Allow AP mode to disconnect STAs based on low ACK condition (when
+ the data connection is not working properly, e.g., due to the STA
+ going outside the range of the AP). Disabled by default, enable by
+ config option disassoc_low_ack.
+ * Add WPA_IGNORE_CONFIG_ERRORS build option to continue in case of bad
+ config file.
+ * WPS:
+ - Send AP Settings as a wrapped Credential attribute to ctrl_iface
+ in WPS-NEW-AP-SETTINGS.
+ - Dispatch more WPS events through hostapd ctrl_iface.
+ - Add mechanism for indicating non-standard WPS errors.
+ - Change concurrent radio AP to use only one WPS UPnP instance.
+ - Add wps_check_pin command for processing PIN from user input.
+ UIs can use this command to process a PIN entered by a user and to
+ validate the checksum digit (if present).
+ - Add hostap_cli get_config command to display current AP config.
+ - Add new hostapd_cli command, wps_ap_pin, to manage AP PIN at
+ runtime and support dynamic AP PIN management.
+ - Disable AP PIN after 10 consecutive failures. Slow down attacks
+ on failures up to 10.
+ - Allow AP to start in Enrollee mode without AP PIN for probing,
+ to be compatible with Windows 7.
+ - Add Config Error into WPS-FAIL events to provide more info
+ to the user on how to resolve the issue.
+ - When controlling multiple interfaces:
+ - apply WPS commands to all interfaces configured to use WPS
+ - apply WPS config changes to all interfaces that use WPS
+ - when an attack is detected on any interface, disable AP PIN on
+ all interfaces
+ * WPS ER:
+ - Show SetSelectedRegistrar events as ctrl_iface events.
+ - Add special AP Setup Locked mode to allow read only ER.
+ ap_setup_locked=2 can now be used to enable a special mode where
+ WPS ER can learn the current AP settings, but cannot change them.
+ * WPS 2.0: Add support for WPS 2.0 (CONFIG_WPS2)
+ - Add build option CONFIG_WPS_EXTENSIBILITY_TESTING to enable tool
+ for testing protocol extensibility.
+ - Add build option CONFIG_WPS_STRICT to allow disabling of WPS
+ workarounds.
+ - Add support for AuthorizedMACs attribute.
+ * TDLS:
+ - Allow TDLS use or TDLS channel switching in the BSS to be
+ prohibited in the BSS, using config params tdls_prohibit and
+ tdls_prohibit_chan_switch.
+ * EAP server: Add support for configuring fragment size (see
+ fragment_size in hostapd.conf).
+ * wlantest: Add a tool wlantest for IEEE802.11 protocol testing.
+ wlantest can be used to capture frames from a monitor interface
+ for realtime capturing or from pcap files for offline analysis.
+ * Interworking: Support added for 802.11u. Enable in .config with
+ CONFIG_INTERWORKING. See hostapd.conf for config parameters for
+ interworking.
+ * Android: Add build and runtime support for Android hostapd.
+ * Add a new debug message level for excessive information. Use
+ -ddd to enable.
+ * TLS: Add support for tls_disable_time_checks=1 in client mode.
+ * Internal TLS:
+ - Add support for TLS v1.1 (RFC 4346). Enable with build parameter
+ CONFIG_TLSV11.
+ - Add domainComponent parser for X.509 names
+ * Reorder some IEs to get closer to IEEE 802.11 standard. Move
+ WMM into end of Beacon, Probe Resp and (Re)Assoc Resp frames.
+ Move HT IEs to be later in (Re)Assoc Resp.
+ * Many bugfixes.
+
2010-04-18 - v0.7.2
* fix WPS internal Registrar use when an external Registrar is also
active
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 22c09c1..b43aa75 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -110,6 +110,7 @@
else
OBJS += ../src/radius/radius.o
OBJS += ../src/radius/radius_client.o
+OBJS += ../src/radius/radius_das.o
endif
ifdef CONFIG_NO_ACCOUNTING
@@ -168,6 +169,14 @@
CFLAGS += -DCONFIG_IEEE80211N
endif
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+endif
+
+ifdef CONFIG_IEEE80211AC
+CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
include ../src/drivers/drivers.mak
OBJS += $(DRV_AP_OBJS)
CFLAGS += $(DRV_AP_CFLAGS)
@@ -752,6 +761,10 @@
OBJS += ../src/ap/ieee802_11_ht.o
endif
+ifdef CONFIG_IEEE80211AC
+OBJS += ../src/ap/ieee802_11_vht.o
+endif
+
ifdef CONFIG_P2P_MANAGER
CFLAGS += -DCONFIG_P2P_MANAGER
OBJS += ../src/ap/p2p_hostapd.o
@@ -759,6 +772,8 @@
ifdef CONFIG_INTERWORKING
CFLAGS += -DCONFIG_INTERWORKING
+OBJS += ../src/common/gas.o
+OBJS += ../src/ap/gas_serv.o
endif
OBJS += ../src/drivers/driver_common.o
diff --git a/hostapd/README-WPS b/hostapd/README-WPS
index 17988d4..87a6f91 100644
--- a/hostapd/README-WPS
+++ b/hostapd/README-WPS
@@ -66,6 +66,10 @@
CONFIG_WPS2=y
CONFIG_WPS_UPNP=y
+Following parameter can be used to enable support for NFC config method:
+
+CONFIG_WPS_NFC=y
+
Following section shows an example runtime configuration
(hostapd.conf) that enables WPS:
@@ -289,3 +293,48 @@
This can be used to update the externally stored AP configuration and
then update hostapd configuration (followed by restarting of hostapd).
+
+
+WPS with NFC
+------------
+
+WPS can be used with NFC-based configuration method. An NFC tag
+containing a password token from the Enrollee can be used to
+authenticate the connection instead of the PIN. In addition, an NFC tag
+with a configuration token can be used to transfer AP settings without
+going through the WPS protocol.
+
+When the AP acts as an Enrollee, a local NFC tag with a password token
+can be used by touching the NFC interface of an external Registrar. The
+wps_nfc_token command is used to manage use of the NFC password token
+from the AP. "wps_nfc_token enable" enables the use of the AP's NFC
+password token (in place of AP PIN) and "wps_nfc_token disable" disables
+the NFC password token.
+
+The NFC password token that is either pre-configured in the
+configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey,
+wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
+"wps_nfc_token <WPS|NDEF>" command. The nfc_pw_token tool from
+wpa_supplicant can be used to generate NFC password tokens during
+manufacturing (each AP needs to have its own random keys).
+
+The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
+NFC configuration token. The output value from this command is a hexdump
+of the current AP configuration (WPS parameter requests this to include
+only the WPS attributes; NDEF parameter requests additional NDEF
+encapsulation to be included). This data needs to be written to an NFC
+tag with an external program. Once written, the NFC configuration token
+can be used to touch an NFC interface on a station to provision the
+credentials needed to access the network.
+
+When the NFC device on the AP reads an NFC tag with a MIME media type
+"application/vnd.wfa.wsc", the NDEF message payload (with or without
+NDEF encapsulation) can be delivered to hostapd using the
+following hostapd_cli command:
+
+wps_nfc_tag_read <hexdump of payload>
+
+If the NFC tag contains a password token, the token is added to the
+internal Registrar. This allows station Enrollee from which the password
+token was received to run through WPS protocol to provision the
+credential.
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 78f1e3d..eebbaa6 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration file parser
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -491,6 +491,104 @@
return ret;
}
+
+
+static struct hostapd_radius_attr *
+hostapd_parse_radius_attr(const char *value)
+{
+ const char *pos;
+ char syntax;
+ struct hostapd_radius_attr *attr;
+ size_t len;
+
+ attr = os_zalloc(sizeof(*attr));
+ if (attr == NULL)
+ return NULL;
+
+ attr->type = atoi(value);
+
+ pos = os_strchr(value, ':');
+ if (pos == NULL) {
+ attr->val = wpabuf_alloc(1);
+ if (attr->val == NULL) {
+ os_free(attr);
+ return NULL;
+ }
+ wpabuf_put_u8(attr->val, 0);
+ return attr;
+ }
+
+ pos++;
+ if (pos[0] == '\0' || pos[1] != ':') {
+ os_free(attr);
+ return NULL;
+ }
+ syntax = *pos++;
+ pos++;
+
+ switch (syntax) {
+ case 's':
+ attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
+ break;
+ case 'x':
+ len = os_strlen(pos);
+ if (len & 1)
+ break;
+ len /= 2;
+ attr->val = wpabuf_alloc(len);
+ if (attr->val == NULL)
+ break;
+ if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
+ wpabuf_free(attr->val);
+ os_free(attr);
+ return NULL;
+ }
+ break;
+ case 'd':
+ attr->val = wpabuf_alloc(4);
+ if (attr->val)
+ wpabuf_put_be32(attr->val, atoi(pos));
+ break;
+ default:
+ os_free(attr);
+ return NULL;
+ }
+
+ if (attr->val == NULL) {
+ os_free(attr);
+ return NULL;
+ }
+
+ return attr;
+}
+
+
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
+ const char *val)
+{
+ char *secret;
+ size_t len;
+
+ secret = os_strchr(val, ' ');
+ if (secret == NULL)
+ return -1;
+
+ secret++;
+ len = os_strlen(secret);
+
+ if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
+ return -1;
+
+ os_free(bss->radius_das_shared_secret);
+ bss->radius_das_shared_secret = os_malloc(len);
+ if (bss->radius_das_shared_secret == NULL)
+ return -1;
+
+ os_memcpy(bss->radius_das_shared_secret, secret, len);
+ bss->radius_das_shared_secret_len = len;
+
+ return 0;
+}
#endif /* CONFIG_NO_RADIUS */
@@ -1034,6 +1132,71 @@
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+static int hostapd_config_vht_capab(struct hostapd_config *conf,
+ const char *capab)
+{
+ if (os_strstr(capab, "[MAX-MPDU-7991]"))
+ conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_7991;
+ if (os_strstr(capab, "[MAX-MPDU-11454]"))
+ conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_11454;
+ if (os_strstr(capab, "[VHT160]"))
+ conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ if (os_strstr(capab, "[VHT160-80PLUS80]"))
+ conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ if (os_strstr(capab, "[VHT160-80PLUS80]"))
+ conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ if (os_strstr(capab, "[RXLDPC]"))
+ conf->vht_capab |= VHT_CAP_RXLDPC;
+ if (os_strstr(capab, "[SHORT-GI-80]"))
+ conf->vht_capab |= VHT_CAP_SHORT_GI_80;
+ if (os_strstr(capab, "[SHORT-GI-160]"))
+ conf->vht_capab |= VHT_CAP_SHORT_GI_160;
+ if (os_strstr(capab, "[TX-STBC-2BY1]"))
+ conf->vht_capab |= VHT_CAP_TXSTBC;
+ if (os_strstr(capab, "[RX-STBC-1]"))
+ conf->vht_capab |= VHT_CAP_RXSTBC_1;
+ if (os_strstr(capab, "[RX-STBC-12]"))
+ conf->vht_capab |= VHT_CAP_RXSTBC_2;
+ if (os_strstr(capab, "[RX-STBC-123]"))
+ conf->vht_capab |= VHT_CAP_RXSTBC_3;
+ if (os_strstr(capab, "[RX-STBC-1234]"))
+ conf->vht_capab |= VHT_CAP_RXSTBC_4;
+ if (os_strstr(capab, "[SU-BEAMFORMER]"))
+ conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+ if (os_strstr(capab, "[SU-BEAMFORMEE]"))
+ conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+ if (os_strstr(capab, "[BF-ANTENNA-2]") &&
+ (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+ conf->vht_capab |= VHT_CAP_BEAMFORMER_ANTENNAS_MAX;
+ if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
+ (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+ conf->vht_capab |= VHT_CAP_SOUNDING_DIMENTION_MAX;
+ if (os_strstr(capab, "[MU-BEAMFORMER]"))
+ conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+ if (os_strstr(capab, "[MU-BEAMFORMEE]"))
+ conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+ if (os_strstr(capab, "[VHT-TXOP-PS]"))
+ conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
+ if (os_strstr(capab, "[HTC-VHT]"))
+ conf->vht_capab |= VHT_CAP_HTC_VHT;
+ if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]"))
+ conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT;
+ if (os_strstr(capab, "[VHT-LINK-ADAPT2]") &&
+ (conf->vht_capab & VHT_CAP_HTC_VHT))
+ conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB;
+ if (os_strstr(capab, "[VHT-LINK-ADAPT3]") &&
+ (conf->vht_capab & VHT_CAP_HTC_VHT))
+ conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
+ if (os_strstr(capab, "[RX-ANTENNA-PATTERN]"))
+ conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN;
+ if (os_strstr(capab, "[TX-ANTENNA-PATTERN]"))
+ conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN;
+ return 0;
+}
+#endif /* CONFIG_IEEE80211AC */
+
+
static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
struct hostapd_config *conf)
{
@@ -1090,6 +1253,12 @@
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211N
+ if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
+ bss->disable_11n = 1;
+ wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
+ "allowed, disabling HT capabilites");
+ }
+
if (conf->ieee80211n &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
bss->disable_11n = 1;
@@ -1175,76 +1344,84 @@
return 0;
}
+
+
+static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
+ int line)
+{
+ char *sep;
+ size_t clen, nlen;
+ struct hostapd_venue_name *vn;
+
+ sep = os_strchr(pos, ':');
+ if (sep == NULL)
+ goto fail;
+ *sep++ = '\0';
+
+ clen = os_strlen(pos);
+ if (clen < 2)
+ goto fail;
+ nlen = os_strlen(sep);
+ if (nlen > 252)
+ goto fail;
+
+ vn = os_realloc(bss->venue_name,
+ sizeof(struct hostapd_venue_name) *
+ (bss->venue_name_count + 1));
+ if (vn == NULL)
+ return -1;
+
+ bss->venue_name = vn;
+ vn = &bss->venue_name[bss->venue_name_count];
+ bss->venue_name_count++;
+
+ os_memset(vn->lang, 0, sizeof(vn->lang));
+ os_memcpy(vn->lang, pos, clen);
+ vn->name_len = nlen;
+ os_memcpy(vn->name, sep, nlen);
+
+ return 0;
+
+fail:
+ wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
+ line, pos);
+ return -1;
+}
#endif /* CONFIG_INTERWORKING */
-/**
- * hostapd_config_read - Read and parse a configuration file
- * @fname: Configuration file name (including path, if needed)
- * Returns: Allocated configuration data structure
- */
-struct hostapd_config * hostapd_config_read(const char *fname)
+#ifdef CONFIG_WPS_NFC
+static struct wpabuf * hostapd_parse_bin(const char *buf)
{
- struct hostapd_config *conf;
- struct hostapd_bss_config *bss;
- FILE *f;
- char buf[256], *pos;
- int line = 0;
+ size_t len;
+ struct wpabuf *ret;
+
+ len = os_strlen(buf);
+ if (len & 0x01)
+ return NULL;
+ len /= 2;
+
+ ret = wpabuf_alloc(len);
+ if (ret == NULL)
+ return NULL;
+
+ if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
+ wpabuf_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+static int hostapd_config_fill(struct hostapd_config *conf,
+ struct hostapd_bss_config *bss,
+ char *buf, char *pos, int line)
+{
int errors = 0;
- int pairwise;
- size_t i;
- f = fopen(fname, "r");
- if (f == NULL) {
- wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
- "for reading.", fname);
- return NULL;
- }
-
- conf = hostapd_config_defaults();
- if (conf == NULL) {
- fclose(f);
- return NULL;
- }
-
- /* set default driver based on configuration */
- conf->driver = wpa_drivers[0];
- if (conf->driver == NULL) {
- wpa_printf(MSG_ERROR, "No driver wrappers registered!");
- hostapd_config_free(conf);
- fclose(f);
- return NULL;
- }
-
- bss = conf->last_bss = conf->bss;
-
- while (fgets(buf, sizeof(buf), f)) {
- bss = conf->last_bss;
- line++;
-
- if (buf[0] == '#')
- continue;
- pos = buf;
- while (*pos != '\0') {
- if (*pos == '\n') {
- *pos = '\0';
- break;
- }
- pos++;
- }
- if (buf[0] == '\0')
- continue;
-
- pos = os_strchr(buf, '=');
- if (pos == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
- line, buf);
- errors++;
- continue;
- }
- *pos = '\0';
- pos++;
-
+ {
if (os_strcmp(buf, "interface") == 0) {
os_strlcpy(conf->bss[0].iface, pos,
sizeof(conf->bss[0].iface));
@@ -1446,7 +1623,7 @@
"allocate memory for "
"eap_req_id_text", line);
errors++;
- continue;
+ return errors;
}
bss->eap_req_id_text_len =
os_strlen(bss->eap_req_id_text);
@@ -1566,6 +1743,51 @@
} else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
{
bss->acct_interim_interval = atoi(pos);
+ } else if (os_strcmp(buf, "radius_request_cui") == 0) {
+ bss->radius_request_cui = atoi(pos);
+ } else if (os_strcmp(buf, "radius_auth_req_attr") == 0) {
+ struct hostapd_radius_attr *attr, *a;
+ attr = hostapd_parse_radius_attr(pos);
+ if (attr == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "radius_auth_req_attr", line);
+ errors++;
+ } else if (bss->radius_auth_req_attr == NULL) {
+ bss->radius_auth_req_attr = attr;
+ } else {
+ a = bss->radius_auth_req_attr;
+ while (a->next)
+ a = a->next;
+ a->next = attr;
+ }
+ } else if (os_strcmp(buf, "radius_acct_req_attr") == 0) {
+ struct hostapd_radius_attr *attr, *a;
+ attr = hostapd_parse_radius_attr(pos);
+ if (attr == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "radius_acct_req_attr", line);
+ errors++;
+ } else if (bss->radius_acct_req_attr == NULL) {
+ bss->radius_acct_req_attr = attr;
+ } else {
+ a = bss->radius_acct_req_attr;
+ while (a->next)
+ a = a->next;
+ a->next = attr;
+ }
+ } else if (os_strcmp(buf, "radius_das_port") == 0) {
+ bss->radius_das_port = atoi(pos);
+ } else if (os_strcmp(buf, "radius_das_client") == 0) {
+ if (hostapd_parse_das_client(bss, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "DAS client", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "radius_das_time_window") == 0) {
+ bss->radius_das_time_window = atoi(pos);
+ } else if (os_strcmp(buf, "radius_das_require_event_timestamp")
+ == 0) {
+ bss->radius_das_require_event_timestamp = atoi(pos);
#endif /* CONFIG_NO_RADIUS */
} else if (os_strcmp(buf, "auth_algs") == 0) {
bss->auth_algs = atoi(pos);
@@ -1605,6 +1827,8 @@
} else {
os_free(bss->ssid.wpa_passphrase);
bss->ssid.wpa_passphrase = os_strdup(pos);
+ os_free(bss->ssid.wpa_psk);
+ bss->ssid.wpa_psk = NULL;
}
} else if (os_strcmp(buf, "wpa_psk") == 0) {
os_free(bss->ssid.wpa_psk);
@@ -1620,6 +1844,8 @@
errors++;
} else {
bss->ssid.wpa_psk->group = 1;
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = NULL;
}
} else if (os_strcmp(buf, "wpa_psk_file") == 0) {
os_free(bss->ssid.wpa_psk_file);
@@ -1690,7 +1916,7 @@
wpa_printf(MSG_DEBUG, "Line %d: Invalid "
"mobility_domain '%s'", line, pos);
errors++;
- continue;
+ return errors;
}
} else if (os_strcmp(buf, "r1_key_holder") == 0) {
if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
@@ -1699,7 +1925,7 @@
wpa_printf(MSG_DEBUG, "Line %d: Invalid "
"r1_key_holder '%s'", line, pos);
errors++;
- continue;
+ return errors;
}
} else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
bss->r0_key_lifetime = atoi(pos);
@@ -1710,14 +1936,14 @@
wpa_printf(MSG_DEBUG, "Line %d: Invalid "
"r0kh '%s'", line, pos);
errors++;
- continue;
+ return errors;
}
} else if (os_strcmp(buf, "r1kh") == 0) {
if (add_r1kh(bss, pos) < 0) {
wpa_printf(MSG_DEBUG, "Line %d: Invalid "
"r1kh '%s'", line, pos);
errors++;
- continue;
+ return errors;
}
} else if (os_strcmp(buf, "pmk_r1_push") == 0) {
bss->pmk_r1_push = atoi(pos);
@@ -1741,7 +1967,7 @@
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
" (from group name '%s')",
bss->ctrl_interface_gid, group);
- continue;
+ return errors;
}
/* Group name not found - try to parse this as gid */
@@ -1750,7 +1976,7 @@
wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
"'%s'", line, group);
errors++;
- continue;
+ return errors;
}
bss->ctrl_interface_gid_set = 1;
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
@@ -1965,6 +2191,18 @@
} else if (os_strcmp(buf, "require_ht") == 0) {
conf->require_ht = atoi(pos);
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ } else if (os_strcmp(buf, "ieee80211ac") == 0) {
+ conf->ieee80211ac = atoi(pos);
+ } else if (os_strcmp(buf, "vht_capab") == 0) {
+ if (hostapd_config_vht_capab(conf, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "vht_capab", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
+ conf->vht_oper_chwidth = atoi(pos);
+#endif /* CONFIG_IEEE80211AC */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
} else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
@@ -2088,6 +2326,25 @@
bss->upc = os_strdup(pos);
} else if (os_strcmp(buf, "pbc_in_m1") == 0) {
bss->pbc_in_m1 = atoi(pos);
+#ifdef CONFIG_WPS_NFC
+ } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
+ bss->wps_nfc_dev_pw_id = atoi(pos);
+ if (bss->wps_nfc_dev_pw_id < 0x10 ||
+ bss->wps_nfc_dev_pw_id > 0xffff) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "wps_nfc_dev_pw_id value", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
+ wpabuf_free(bss->wps_nfc_dh_pubkey);
+ bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+ } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
+ wpabuf_free(bss->wps_nfc_dh_privkey);
+ bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+ } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
+ wpabuf_free(bss->wps_nfc_dev_pw);
+ bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P_MANAGER
} else if (os_strcmp(buf, "manage_p2p") == 0) {
@@ -2129,7 +2386,7 @@
wpa_printf(MSG_DEBUG, "Line %d: invalid "
"time_zone", line);
errors++;
- continue;
+ return errors;
}
os_free(bss->time_zone);
bss->time_zone = os_strdup(pos);
@@ -2169,6 +2426,13 @@
} else if (os_strcmp(buf, "roaming_consortium") == 0) {
if (parse_roaming_consortium(bss, pos, line) < 0)
errors++;
+ } else if (os_strcmp(buf, "venue_name") == 0) {
+ if (parse_venue_name(bss, pos, line) < 0)
+ errors++;
+ } else if (os_strcmp(buf, "gas_frag_limit") == 0) {
+ bss->gas_frag_limit = atoi(pos);
+ } else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
+ bss->gas_comeback_delay = atoi(pos);
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_RADIUS_TEST
} else if (os_strcmp(buf, "dump_msk_file") == 0) {
@@ -2182,64 +2446,141 @@
}
}
+ return errors;
+}
+
+
+static void hostapd_set_security_params(struct hostapd_bss_config *bss)
+{
+ int pairwise;
+
+ if (bss->individual_wep_key_len == 0) {
+ /* individual keys are not use; can use key idx0 for
+ * broadcast keys */
+ bss->broadcast_key_idx_min = 0;
+ }
+
+ /* Select group cipher based on the enabled pairwise cipher
+ * suites */
+ pairwise = 0;
+ if (bss->wpa & 1)
+ pairwise |= bss->wpa_pairwise;
+ if (bss->wpa & 2) {
+ if (bss->rsn_pairwise == 0)
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ pairwise |= bss->rsn_pairwise;
+ }
+ if (pairwise & WPA_CIPHER_TKIP)
+ bss->wpa_group = WPA_CIPHER_TKIP;
+ else
+ bss->wpa_group = WPA_CIPHER_CCMP;
+
+ bss->radius->auth_server = bss->radius->auth_servers;
+ bss->radius->acct_server = bss->radius->acct_servers;
+
+ if (bss->wpa && bss->ieee802_1x) {
+ bss->ssid.security_policy = SECURITY_WPA;
+ } else if (bss->wpa) {
+ bss->ssid.security_policy = SECURITY_WPA_PSK;
+ } else if (bss->ieee802_1x) {
+ int cipher = WPA_CIPHER_NONE;
+ bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+ bss->ssid.wep.default_len = bss->default_wep_key_len;
+ if (bss->default_wep_key_len)
+ cipher = bss->default_wep_key_len >= 13 ?
+ WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+ bss->wpa_group = cipher;
+ bss->wpa_pairwise = cipher;
+ bss->rsn_pairwise = cipher;
+ } else if (bss->ssid.wep.keys_set) {
+ int cipher = WPA_CIPHER_WEP40;
+ if (bss->ssid.wep.len[0] >= 13)
+ cipher = WPA_CIPHER_WEP104;
+ bss->ssid.security_policy = SECURITY_STATIC_WEP;
+ bss->wpa_group = cipher;
+ bss->wpa_pairwise = cipher;
+ bss->rsn_pairwise = cipher;
+ } else {
+ bss->ssid.security_policy = SECURITY_PLAINTEXT;
+ bss->wpa_group = WPA_CIPHER_NONE;
+ bss->wpa_pairwise = WPA_CIPHER_NONE;
+ bss->rsn_pairwise = WPA_CIPHER_NONE;
+ }
+}
+
+
+/**
+ * hostapd_config_read - Read and parse a configuration file
+ * @fname: Configuration file name (including path, if needed)
+ * Returns: Allocated configuration data structure
+ */
+struct hostapd_config * hostapd_config_read(const char *fname)
+{
+ struct hostapd_config *conf;
+ struct hostapd_bss_config *bss;
+ FILE *f;
+ char buf[512], *pos;
+ int line = 0;
+ int errors = 0;
+ size_t i;
+
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
+ "for reading.", fname);
+ return NULL;
+ }
+
+ conf = hostapd_config_defaults();
+ if (conf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+
+ /* set default driver based on configuration */
+ conf->driver = wpa_drivers[0];
+ if (conf->driver == NULL) {
+ wpa_printf(MSG_ERROR, "No driver wrappers registered!");
+ hostapd_config_free(conf);
+ fclose(f);
+ return NULL;
+ }
+
+ bss = conf->last_bss = conf->bss;
+
+ while (fgets(buf, sizeof(buf), f)) {
+ bss = conf->last_bss;
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ pos = os_strchr(buf, '=');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
+ line, buf);
+ errors++;
+ continue;
+ }
+ *pos = '\0';
+ pos++;
+ errors += hostapd_config_fill(conf, bss, buf, pos, line);
+ }
+
fclose(f);
- for (i = 0; i < conf->num_bss; i++) {
- bss = &conf->bss[i];
-
- if (bss->individual_wep_key_len == 0) {
- /* individual keys are not use; can use key idx0 for
- * broadcast keys */
- bss->broadcast_key_idx_min = 0;
- }
-
- /* Select group cipher based on the enabled pairwise cipher
- * suites */
- pairwise = 0;
- if (bss->wpa & 1)
- pairwise |= bss->wpa_pairwise;
- if (bss->wpa & 2) {
- if (bss->rsn_pairwise == 0)
- bss->rsn_pairwise = bss->wpa_pairwise;
- pairwise |= bss->rsn_pairwise;
- }
- if (pairwise & WPA_CIPHER_TKIP)
- bss->wpa_group = WPA_CIPHER_TKIP;
- else
- bss->wpa_group = WPA_CIPHER_CCMP;
-
- bss->radius->auth_server = bss->radius->auth_servers;
- bss->radius->acct_server = bss->radius->acct_servers;
-
- if (bss->wpa && bss->ieee802_1x) {
- bss->ssid.security_policy = SECURITY_WPA;
- } else if (bss->wpa) {
- bss->ssid.security_policy = SECURITY_WPA_PSK;
- } else if (bss->ieee802_1x) {
- int cipher = WPA_CIPHER_NONE;
- bss->ssid.security_policy = SECURITY_IEEE_802_1X;
- bss->ssid.wep.default_len = bss->default_wep_key_len;
- if (bss->default_wep_key_len)
- cipher = bss->default_wep_key_len >= 13 ?
- WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
- bss->wpa_group = cipher;
- bss->wpa_pairwise = cipher;
- bss->rsn_pairwise = cipher;
- } else if (bss->ssid.wep.keys_set) {
- int cipher = WPA_CIPHER_WEP40;
- if (bss->ssid.wep.len[0] >= 13)
- cipher = WPA_CIPHER_WEP104;
- bss->ssid.security_policy = SECURITY_STATIC_WEP;
- bss->wpa_group = cipher;
- bss->wpa_pairwise = cipher;
- bss->rsn_pairwise = cipher;
- } else {
- bss->ssid.security_policy = SECURITY_PLAINTEXT;
- bss->wpa_group = WPA_CIPHER_NONE;
- bss->wpa_pairwise = WPA_CIPHER_NONE;
- bss->rsn_pairwise = WPA_CIPHER_NONE;
- }
- }
+ for (i = 0; i < conf->num_bss; i++)
+ hostapd_set_security_params(&conf->bss[i]);
if (hostapd_config_check(conf))
errors++;
@@ -2255,3 +2596,28 @@
return conf;
}
+
+
+int hostapd_set_iface(struct hostapd_config *conf,
+ struct hostapd_bss_config *bss, char *field, char *value)
+{
+ int errors;
+ size_t i;
+
+ errors = hostapd_config_fill(conf, bss, field, value, 0);
+ if (errors) {
+ wpa_printf(MSG_INFO, "Failed to set configuration field '%s' "
+ "to value '%s'", field, value);
+ return -1;
+ }
+
+ for (i = 0; i < conf->num_bss; i++)
+ hostapd_set_security_params(&conf->bss[i]);
+
+ if (hostapd_config_check(conf)) {
+ wpa_printf(MSG_ERROR, "Configuration check failed");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/hostapd/config_file.h b/hostapd/config_file.h
index 80d182e..fba57b8 100644
--- a/hostapd/config_file.h
+++ b/hostapd/config_file.h
@@ -10,5 +10,8 @@
#define CONFIG_FILE_H
struct hostapd_config * hostapd_config_read(const char *fname);
+int hostapd_set_iface(struct hostapd_config *conf,
+ struct hostapd_bss_config *bss, char *field,
+ char *value);
#endif /* CONFIG_FILE_H */
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 9d5a67e..7587e03 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-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -31,6 +31,7 @@
#include "ap/ap_drv_ops.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
+#include "config_file.h"
#include "ctrl_iface.h"
@@ -152,173 +153,6 @@
}
-#ifdef CONFIG_P2P_MANAGER
-static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
- u8 minor_reason_code, const u8 *addr)
-{
- struct ieee80211_mgmt *mgmt;
- int ret;
- u8 *pos;
-
- if (hapd->driver->send_frame == NULL)
- return -1;
-
- mgmt = os_zalloc(sizeof(*mgmt) + 100);
- if (mgmt == NULL)
- return -1;
-
- wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
- " with minor reason code %u (stype=%u)",
- MAC2STR(addr), minor_reason_code, stype);
-
- mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
- 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);
- if (stype == WLAN_FC_STYPE_DEAUTH) {
- mgmt->u.deauth.reason_code =
- host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
- } else {
- mgmt->u.disassoc.reason_code =
- host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
- }
-
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = 4 + 3 + 1;
- WPA_PUT_BE24(pos, OUI_WFA);
- pos += 3;
- *pos++ = P2P_OUI_TYPE;
-
- *pos++ = P2P_ATTR_MINOR_REASON_CODE;
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- *pos++ = minor_reason_code;
-
- ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
- pos - (u8 *) mgmt, 1);
- os_free(mgmt);
-
- return ret < 0 ? -1 : 0;
-}
-#endif /* CONFIG_P2P_MANAGER */
-
-
-static int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
- const char *txtaddr)
-{
- u8 addr[ETH_ALEN];
- struct sta_info *sta;
- const char *pos;
-
- wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
- txtaddr);
-
- if (hwaddr_aton(txtaddr, addr))
- return -1;
-
- pos = os_strstr(txtaddr, " test=");
- if (pos) {
- struct ieee80211_mgmt mgmt;
- int encrypt;
- if (hapd->driver->send_frame == NULL)
- return -1;
- pos += 6;
- encrypt = atoi(pos);
- os_memset(&mgmt, 0, sizeof(mgmt));
- mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_DEAUTH);
- 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.deauth.reason_code =
- host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
- return -1;
- return 0;
- }
-
-#ifdef CONFIG_P2P_MANAGER
- pos = os_strstr(txtaddr, " p2p=");
- if (pos) {
- return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
- atoi(pos + 5), addr);
- }
-#endif /* CONFIG_P2P_MANAGER */
-
- hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
- sta = ap_get_sta(hapd, addr);
- if (sta)
- ap_sta_deauthenticate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
- else if (addr[0] == 0xff)
- hostapd_free_stas(hapd);
-
- return 0;
-}
-
-
-static int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
- const char *txtaddr)
-{
- u8 addr[ETH_ALEN];
- struct sta_info *sta;
- const char *pos;
-
- wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
- txtaddr);
-
- if (hwaddr_aton(txtaddr, addr))
- return -1;
-
- pos = os_strstr(txtaddr, " test=");
- if (pos) {
- struct ieee80211_mgmt mgmt;
- int encrypt;
- if (hapd->driver->send_frame == NULL)
- return -1;
- pos += 6;
- encrypt = atoi(pos);
- os_memset(&mgmt, 0, sizeof(mgmt));
- mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_DISASSOC);
- 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.disassoc.reason_code =
- host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
- return -1;
- return 0;
- }
-
-#ifdef CONFIG_P2P_MANAGER
- pos = os_strstr(txtaddr, " p2p=");
- if (pos) {
- return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
- atoi(pos + 5), addr);
- }
-#endif /* CONFIG_P2P_MANAGER */
-
- hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
- sta = ap_get_sta(hapd, addr);
- if (sta)
- ap_sta_disassociate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
- else if (addr[0] == 0xff)
- hostapd_free_stas(hapd);
-
- return 0;
-}
-
-
#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
@@ -440,6 +274,111 @@
#endif /* CONFIG_WPS_OOB */
+#ifdef CONFIG_WPS_NFC
+static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
+ char *pos)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = hostapd_wps_nfc_tag_read(hapd, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ int ndef;
+ struct wpabuf *buf;
+ int res;
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ buf = hostapd_wps_nfc_config_token(hapd, ndef);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
+ char *reply, size_t max_len,
+ int ndef)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = hostapd_wps_nfc_token_gen(hapd, ndef);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ if (os_strcmp(cmd, "WPS") == 0)
+ return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+ max_len, 0);
+
+ if (os_strcmp(cmd, "NDEF") == 0)
+ return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+ max_len, 1);
+
+ if (os_strcmp(cmd, "enable") == 0)
+ return hostapd_wps_nfc_token_enable(hapd);
+
+ if (os_strcmp(cmd, "disable") == 0) {
+ hostapd_wps_nfc_token_disable(hapd);
+ return 0;
+ }
+
+ return -1;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
char *buf, size_t buflen)
{
@@ -773,8 +712,16 @@
wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
wps_testing_dummy_cred);
#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_INTERWORKING
+ } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
+ int val = atoi(value);
+ if (val <= 0)
+ ret = -1;
+ else
+ hapd->gas_frag_limit = val;
+#endif /* CONFIG_INTERWORKING */
} else {
- ret = -1;
+ ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
}
return ret;
@@ -913,6 +860,9 @@
} else if (os_strcmp(buf, "WPS_PBC") == 0) {
if (hostapd_wps_button_pushed(hapd, NULL))
reply_len = -1;
+ } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
+ if (hostapd_wps_cancel(hapd))
+ reply_len = -1;
#ifdef CONFIG_WPS_OOB
} else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
@@ -924,6 +874,17 @@
} else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+ } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
+ if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
+ reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
+ hapd, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+ reply_len = hostapd_ctrl_iface_wps_nfc_token(
+ hapd, buf + 14, reply, reply_size);
+#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
@@ -988,7 +949,10 @@
int s = -1;
char *fname = NULL;
- hapd->ctrl_sock = -1;
+ if (hapd->ctrl_sock > -1) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+ return 0;
+ }
if (hapd->conf->ctrl_interface == NULL)
return 0;
@@ -1045,7 +1009,7 @@
}
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
- perror("bind(PF_UNIX)");
+ perror("hostapd-ctrl-iface: bind(PF_UNIX)");
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 3cf0d13..9c5b13a 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -108,6 +108,8 @@
#CONFIG_WPS2=y
# Enable UPnP support for external WPS Registrars
#CONFIG_WPS_UPNP=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
@@ -136,6 +138,13 @@
# IEEE 802.11n (High Throughput) support
#CONFIG_IEEE80211N=y
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
+# IEEE 802.11ac (Very High Throughput) support
+#CONFIG_IEEE80211AC=y
+
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed.
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index b59ea1b..516d859 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -1,6 +1,6 @@
/*
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -34,7 +34,11 @@
* text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
* strings. This is used to simulate an HLR/AuC. As such, it is not very useful
* for real life authentication, but it is useful both as an example
- * implementation and for EAP-SIM testing.
+ * implementation and for EAP-SIM/AKA/AKA' testing.
+ *
+ * SQN generation follows the not time-based Profile 2 described in
+ * 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
+ * can be changed with a command line options if needed.
*/
#include "includes.h"
@@ -47,6 +51,10 @@
static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
static const char *socket_path;
static int serv_sock = -1;
+static char *milenage_file = NULL;
+static int update_milenage = 0;
+static int sqn_changes = 0;
+static int ind_len = 5;
/* GSM triplets */
struct gsm_triplet {
@@ -96,7 +104,7 @@
addr.sun_family = AF_UNIX;
os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ perror("hlr-auc-gw: bind(PF_UNIX)");
close(s);
return -1;
}
@@ -210,7 +218,7 @@
gsm_db = g;
g = NULL;
}
- free(g);
+ os_free(g);
fclose(f);
@@ -360,7 +368,7 @@
milenage_db = m;
m = NULL;
}
- free(m);
+ os_free(m);
fclose(f);
@@ -368,6 +376,80 @@
}
+static void update_milenage_file(const char *fname)
+{
+ FILE *f, *f2;
+ char buf[500], *pos;
+ char *end = buf + sizeof(buf);
+ struct milenage_parameters *m;
+ size_t imsi_len;
+
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ printf("Could not open Milenage data file '%s'\n", fname);
+ return;
+ }
+
+ snprintf(buf, sizeof(buf), "%s.new", fname);
+ f2 = fopen(buf, "w");
+ if (f2 == NULL) {
+ printf("Could not write Milenage data file '%s'\n", buf);
+ fclose(f);
+ return;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ /* IMSI Ki OPc AMF SQN */
+ buf[sizeof(buf) - 1] = '\0';
+
+ pos = strchr(buf, ' ');
+ if (buf[0] == '#' || pos == NULL || pos - buf >= 20)
+ goto no_update;
+
+ imsi_len = pos - buf;
+
+ for (m = milenage_db; m; m = m->next) {
+ if (strncmp(buf, m->imsi, imsi_len) == 0 &&
+ m->imsi[imsi_len] == '\0')
+ break;
+ }
+
+ if (!m)
+ goto no_update;
+
+ pos = buf;
+ pos += snprintf(pos, end - pos, "%s ", m->imsi);
+ pos += wpa_snprintf_hex(pos, end - pos, m->ki, 16);
+ *pos++ = ' ';
+ pos += wpa_snprintf_hex(pos, end - pos, m->opc, 16);
+ *pos++ = ' ';
+ pos += wpa_snprintf_hex(pos, end - pos, m->amf, 2);
+ *pos++ = ' ';
+ pos += wpa_snprintf_hex(pos, end - pos, m->sqn, 6);
+ *pos++ = '\n';
+
+ no_update:
+ fprintf(f2, "%s", buf);
+ }
+
+ fclose(f2);
+ fclose(f);
+
+ snprintf(buf, sizeof(buf), "%s.bak", fname);
+ if (rename(fname, buf) < 0) {
+ perror("rename");
+ return;
+ }
+
+ snprintf(buf, sizeof(buf), "%s.new", fname);
+ if (rename(buf, fname) < 0) {
+ perror("rename");
+ return;
+ }
+
+}
+
+
static struct milenage_parameters * get_milenage(const char *imsi)
{
struct milenage_parameters *m = milenage_db;
@@ -460,6 +542,28 @@
}
+static void inc_sqn(u8 *sqn)
+{
+ u64 val, seq, ind;
+
+ /*
+ * SQN = SEQ | IND = SEQ1 | SEQ2 | IND
+ *
+ * The mechanism used here is not time-based, so SEQ2 is void and
+ * SQN = SEQ1 | IND. The length of IND is ind_len bits and the length
+ * of SEQ1 is 48 - ind_len bits.
+ */
+
+ /* Increment both SEQ and IND by one */
+ val = ((u64) WPA_GET_BE32(sqn) << 16) | ((u64) WPA_GET_BE16(sqn + 4));
+ seq = (val >> ind_len) + 1;
+ ind = (val + 1) & ((1 << ind_len) - 1);
+ val = (seq << ind_len) | ind;
+ WPA_PUT_BE32(sqn, val >> 16);
+ WPA_PUT_BE16(sqn + 4, val & 0xffff);
+}
+
+
static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
char *imsi)
{
@@ -479,7 +583,8 @@
if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
return;
res_len = EAP_AKA_RES_MAX_LEN;
- inc_byte_array(m->sqn, 6);
+ inc_sqn(m->sqn);
+ sqn_changes = 1;
printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
m->sqn[0], m->sqn[1], m->sqn[2],
m->sqn[3], m->sqn[4], m->sqn[5]);
@@ -563,6 +668,7 @@
printf("AKA-AUTS: Re-synchronized: "
"SQN=%02x%02x%02x%02x%02x%02x\n",
sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+ sqn_changes = 1;
}
}
@@ -609,18 +715,21 @@
struct gsm_triplet *g, *gprev;
struct milenage_parameters *m, *prev;
+ if (update_milenage && milenage_file && sqn_changes)
+ update_milenage_file(milenage_file);
+
g = gsm_db;
while (g) {
gprev = g;
g = g->next;
- free(gprev);
+ os_free(gprev);
}
m = milenage_db;
while (m) {
prev = m;
m = m->next;
- free(prev);
+ os_free(prev);
}
close(serv_sock);
@@ -639,18 +748,21 @@
{
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
"database/authenticator\n"
- "Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>\n"
+ "Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>\n"
"\n"
"usage:\n"
- "hlr_auc_gw [-h] [-s<socket path>] [-g<triplet file>] "
- "[-m<milenage file>]\n"
+ "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
+ "[-m<milenage file>] \\\n"
+ " [-i<IND len in bits>]\n"
"\n"
"options:\n"
" -h = show this usage help\n"
+ " -u = update SQN in Milenage file on exit\n"
" -s<socket path> = path for UNIX domain socket\n"
" (default: %s)\n"
" -g<triplet file> = path for GSM authentication triplets\n"
- " -m<milenage file> = path for Milenage keys\n",
+ " -m<milenage file> = path for Milenage keys\n"
+ " -i<IND len in bits> = IND length for SQN (default: 5)\n",
default_socket_path);
}
@@ -658,13 +770,15 @@
int main(int argc, char *argv[])
{
int c;
- char *milenage_file = NULL;
char *gsm_triplet_file = NULL;
+ if (os_program_init())
+ return -1;
+
socket_path = default_socket_path;
for (;;) {
- c = getopt(argc, argv, "g:hm:s:");
+ c = getopt(argc, argv, "g:hi:m:s:u");
if (c < 0)
break;
switch (c) {
@@ -674,12 +788,22 @@
case 'h':
usage();
return 0;
+ case 'i':
+ ind_len = atoi(optarg);
+ if (ind_len < 0 || ind_len > 32) {
+ printf("Invalid IND length\n");
+ return -1;
+ }
+ break;
case 'm':
milenage_file = optarg;
break;
case 's':
socket_path = optarg;
break;
+ case 'u':
+ update_milenage = 1;
+ break;
default:
usage();
return -1;
@@ -705,5 +829,7 @@
for (;;)
process(serv_sock);
+ os_program_deinit();
+
return 0;
}
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 4e6202b..daa03d2 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -416,6 +416,137 @@
# Require stations to support HT PHY (reject association if they do not)
#require_ht=1
+##### IEEE 802.11ac related configuration #####################################
+
+# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full VHT functionality.
+#ieee80211ac=1
+
+# vht_capab: VHT capabilities (list of flags)
+#
+# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
+# Indicates maximum MPDU length
+# 0 = 3895 octets (default)
+# 1 = 7991 octets
+# 2 = 11454 octets
+# 3 = reserved
+#
+# supported_chan_width: [VHT160] [VHT160-80PLUS80]
+# Indicates supported Channel widths
+# 0 = 160 MHz & 80+80 channel widths are not supported (default)
+# 1 = 160 MHz channel width is supported
+# 2 = 160 MHz & 80+80 channel widths are supported
+# 3 = reserved
+#
+# Rx LDPC coding capability: [RXLDPC]
+# Indicates support for receiving LDPC coded pkts
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 80 MHz: [SHORT-GI-80]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 80Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 160 MHz: [SHORT-GI-160]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 160Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Tx STBC: [TX-STBC-2BY1]
+# Indicates support for the transmission of at least 2x1 STBC
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234]
+# Indicates support for the reception of PPDUs using STBC
+# 0 = Not supported (default)
+# 1 = support of one spatial stream
+# 2 = support of one and two spatial streams
+# 3 = support of one, two and three spatial streams
+# 4 = support of one, two, three and four spatial streams
+# 5,6,7 = reserved
+#
+# SU Beamformer Capable: [SU-BEAMFORMER]
+# Indicates support for operation as a single user beamformer
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# SU Beamformee Capable: [SU-BEAMFORMEE]
+# Indicates support for operation as a single user beamformee
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Compressed Steering Number of Beamformer Antennas Supported: [BF-ANTENNA-2]
+# Beamformee's capability indicating the maximum number of beamformer
+# antennas the beamformee can support when sending compressed beamforming
+# feedback
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
+# BeamformerÂ’s capability indicating the maximum value of the NUM_STS parameter
+# in the TXVECTOR of a VHT NDP
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# MU Beamformer Capable: [MU-BEAMFORMER]
+# Indicates support for operation as an MU beamformer
+# 0 = Not supported or sent by Non-AP STA (default)
+# 1 = Supported
+#
+# MU Beamformee Capable: [MU-BEAMFORMEE]
+# Indicates support for operation as an MU beamformee
+# 0 = Not supported or sent by AP (default)
+# 1 = Supported
+#
+# VHT TXOP PS: [VHT-TXOP-PS]
+# Indicates whether or not the AP supports VHT TXOP Power Save Mode
+# or whether or not the STA is in VHT TXOP Power Save mode
+# 0 = VHT AP doesnt support VHT TXOP PS mode (OR) VHT Sta not in VHT TXOP PS
+# mode
+# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save
+# mode
+#
+# +HTC-VHT Capable: [HTC-VHT]
+# Indicates whether or not the STA supports receiving a VHT variant HT Control
+# field.
+# 0 = Not supported (default)
+# 1 = supported
+#
+# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7]
+# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv
+# This field is an integer in the range of 0 to 7.
+# The length defined by this field is equal to
+# 2 pow(13 + Maximum A-MPDU Length Exponent) –1 octets
+#
+# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3]
+# Indicates whether or not the STA supports link adaptation using VHT variant
+# HT Control field
+# If +HTC-VHTcapable is 1
+# 0 = (no feedback) if the STA does not provide VHT MFB (default)
+# 1 = reserved
+# 2 = (Unsolicited) if the STA provides only unsolicited VHT MFB
+# 3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the
+# STA provides unsolicited VHT MFB
+# Reserved if +HTC-VHTcapable is 0
+#
+# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN]
+# Indicates the possibility of Rx antenna pattern change
+# 0 = Rx antenna pattern might change during the lifetime of an association
+# 1 = Rx antenna pattern does not change during the lifetime of an association
+#
+# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN]
+# Indicates the possibility of Tx antenna pattern change
+# 0 = Tx antenna pattern might change during the lifetime of an association
+# 1 = Tx antenna pattern does not change during the lifetime of an association
+#vht_capab=[SHORT-GI-80][HTC-VHT]
+#vht_oper_chwidth=1
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@@ -632,6 +763,12 @@
# 60 (1 minute).
#radius_acct_interim_interval=600
+# Request Chargeable-User-Identity (RFC 4372)
+# This parameter can be used to configure hostapd to request CUI from the
+# RADIUS server by including Chargeable-User-Identity attribute into
+# Access-Request packets.
+#radius_request_cui=1
+
# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
# is used for the stations. This information is parsed from following RADIUS
# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
@@ -659,6 +796,55 @@
# to the bridge.
#vlan_tagged_interface=eth0
+# Arbitrary RADIUS attributes can be added into Access-Request and
+# Accounting-Request packets by specifying the contents of the attributes with
+# the following configuration parameters. There can be multiple of these to
+# add multiple attributes. These parameters can also be used to override some
+# of the attributes added automatically by hostapd.
+# Format: <attr_id>[:<syntax:value>]
+# attr_id: RADIUS attribute type (e.g., 26 = Vendor-Specific)
+# syntax: s = string (UTF-8), d = integer, x = octet string
+# value: attribute value in format indicated by the syntax
+# If syntax and value parts are omitted, a null value (single 0x00 octet) is
+# used.
+#
+# Additional Access-Request attributes
+# radius_auth_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_auth_req_attr=126:s:Operator
+# Service-Type = Framed (2)
+#radius_auth_req_attr=6:d:2
+# Connect-Info = "testing" (this overrides the automatically generated value)
+#radius_auth_req_attr=77:s:testing
+# Same Connect-Info value set as a hexdump
+#radius_auth_req_attr=77:x:74657374696e67
+
+#
+# Additional Accounting-Request attributes
+# radius_acct_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_acct_req_attr=126:s:Operator
+
+# Dynamic Authorization Extensions (RFC 5176)
+# This mechanism can be used to allow dynamic changes to user session based on
+# commands from a RADIUS server (or some other disconnect client that has the
+# needed session information). For example, Disconnect message can be used to
+# request an associated station to be disconnected.
+#
+# This is disabled by default. Set radius_das_port to non-zero UDP port
+# number to enable.
+#radius_das_port=3799
+#
+# DAS client (the host that can send Disconnect/CoA requests) and shared secret
+#radius_das_client=192.168.1.123 shared secret here
+#
+# DAS Event-Timestamp time window in seconds
+#radius_das_time_window=300
+#
+# DAS require Event-Timestamp
+#radius_das_require_event_timestamp=1
##### RADIUS authentication server configuration ##############################
@@ -1033,6 +1219,18 @@
# set to ag to allow both RF bands to be advertized.
#wps_rf_bands=ag
+# NFC password token for WPS
+# These parameters can be used to configure a fixed NFC password token for the
+# AP. This can be generated, e.g., with nfc_pw_token from wpa_supplicant. When
+# these parameters are used, the AP is assumed to be deployed with a NFC tag
+# that includes the matching NFC password token (e.g., written based on the
+# NDEF record from nfc_pw_token).
+#
+#wps_nfc_dev_pw_id: Device Password ID (16..65535)
+#wps_nfc_dh_pubkey: Hexdump of DH Public Key
+#wps_nfc_dh_privkey: Hexdump of DH Private Key
+#wps_nfc_dev_pw: Hexdump of Device Password
+
##### Wi-Fi Direct (P2P) ######################################################
# Enable P2P Device management
@@ -1118,6 +1316,15 @@
#roaming_consortium=021122
#roaming_consortium=2233445566
+# Venue Name information
+# This parameter can be used to configure one or more Venue Name Duples for
+# Venue Name ANQP information. Each entry has a two or three character language
+# code (ISO-639) separated by colon from the venue name string.
+# Note that venue_group and venue_type have to be set for Venue Name
+# information to be complete.
+#venue_name=eng:Example venue
+#venue_name=fin:Esimerkkipaikka
+
##### Multiple BSSID support ##################################################
#
# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
diff --git a/hostapd/hostapd.eap_user b/hostapd/hostapd.eap_user
index ac9a5d8..12a2c61 100644
--- a/hostapd/hostapd.eap_user
+++ b/hostapd/hostapd.eap_user
@@ -69,6 +69,9 @@
"3"* SIM,TTLS,TLS,PEAP,AKA
"4"* AKA,TTLS,TLS,PEAP,SIM
"5"* SIM,TTLS,TLS,PEAP,AKA
+"6"* AKA'
+"7"* AKA'
+"8"* AKA'
# Wildcard for all other identities
* PEAP,TTLS,TLS,SIM,AKA
@@ -89,3 +92,6 @@
"3"* SIM [2]
"4"* AKA [2]
"5"* SIM [2]
+"6"* AKA' [2]
+"7"* AKA' [2]
+"8"* AKA' [2]
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 89125fd..0c33d5b 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-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -74,6 +74,11 @@
#ifdef CONFIG_WPS_OOB
" wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n"
#endif /* CONFIG_WPS_OOB */
+#ifdef CONFIG_WPS_NFC
+" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
+" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
+" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
+#endif /* CONFIG_WPS_NFC */
" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
" wps_config <SSID> <auth> <encr> <key> configure AP\n"
#endif /* CONFIG_WPS */
@@ -392,6 +397,13 @@
}
+static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "WPS_CANCEL");
+}
+
+
#ifdef CONFIG_WPS_OOB
static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
char *argv[])
@@ -426,6 +438,77 @@
#endif /* CONFIG_WPS_OOB */
+#ifdef CONFIG_WPS_NFC
+static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ int ret;
+ char *buf;
+ size_t buflen;
+
+ if (argc != 1) {
+ printf("Invalid 'wps_nfc_tag_read' command - one argument "
+ "is required.\n");
+ return -1;
+ }
+
+ buflen = 18 + os_strlen(argv[0]);
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return -1;
+ os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
+
+ ret = wpa_ctrl_command(ctrl, buf);
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char cmd[64];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid 'wps_nfc_config_token' command - one argument "
+ "is required.\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
+ argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char cmd[64];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid 'wps_nfc_token' command - one argument is "
+ "required.\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long WPS_NFC_TOKEN command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_WPS_NFC */
+
+
static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -719,9 +802,15 @@
{ "wps_pin", hostapd_cli_cmd_wps_pin },
{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
+ { "wps_cancel", hostapd_cli_cmd_wps_cancel },
#ifdef CONFIG_WPS_OOB
{ "wps_oob", hostapd_cli_cmd_wps_oob },
#endif /* CONFIG_WPS_OOB */
+#ifdef CONFIG_WPS_NFC
+ { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
+ { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
+ { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
+#endif /* CONFIG_WPS_NFC */
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
{ "wps_config", hostapd_cli_cmd_wps_config },
#endif /* CONFIG_WPS */
diff --git a/hostapd/main.c b/hostapd/main.c
index 3918737..d8c2776 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -21,6 +21,7 @@
#include "eap_server/tncs.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
#include "config_file.h"
#include "eap_register.h"
#include "dump_state.h"
@@ -42,29 +43,6 @@
static struct hapd_global global;
-struct hapd_interfaces {
- size_t count;
- struct hostapd_iface **iface;
-};
-
-
-static int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
- int (*cb)(struct hostapd_iface *iface,
- void *ctx), void *ctx)
-{
- size_t i;
- int ret;
-
- for (i = 0; i < interfaces->count; i++) {
- ret = cb(interfaces->iface[i], ctx);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-
#ifndef CONFIG_NO_HOSTAPD_LOGGER
static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
int level, const char *txt, size_t len)
@@ -315,7 +293,7 @@
driver = iface->bss[0]->driver;
drv_priv = iface->bss[0]->drv_priv;
hostapd_interface_deinit(iface);
- if (driver && driver->hapd_deinit)
+ if (driver && driver->hapd_deinit && drv_priv)
driver->hapd_deinit(drv_priv);
hostapd_interface_free(iface);
}
@@ -339,10 +317,13 @@
iface->bss[0]->conf->logger_stdout_level--;
}
- if (hostapd_driver_init(iface) ||
- hostapd_setup_interface(iface)) {
- hostapd_interface_deinit_free(iface);
- return NULL;
+ if (iface->conf->bss[0].iface[0] != 0 ||
+ hostapd_drv_none(iface->bss[0])) {
+ if (hostapd_driver_init(iface) ||
+ hostapd_setup_interface(iface)) {
+ hostapd_interface_deinit_free(iface);
+ return NULL;
+ }
}
return iface;
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 2a04560..2c3a6d9 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -1,6 +1,6 @@
/*
* hostapd / RADIUS Accounting
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -39,6 +39,8 @@
u8 *val;
size_t len;
int i;
+ struct wpabuf *b;
+ struct hostapd_radius_attr *attr;
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
@@ -67,7 +69,9 @@
goto fail;
}
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_ACCT_AUTHENTIC) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
hapd->conf->ieee802_1x ?
RADIUS_ACCT_AUTHENTIC_RADIUS :
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
@@ -91,7 +95,9 @@
}
}
- if (hapd->conf->own_ip_addr.af == AF_INET &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_NAS_IP_ADDRESS) &&
+ hapd->conf->own_ip_addr.af == AF_INET &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
printf("Could not add NAS-IP-Address\n");
@@ -99,7 +105,9 @@
}
#ifdef CONFIG_IPV6
- if (hapd->conf->own_ip_addr.af == AF_INET6 &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
+ hapd->conf->own_ip_addr.af == AF_INET6 &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
printf("Could not add NAS-IPv6-Address\n");
@@ -107,7 +115,9 @@
}
#endif /* CONFIG_IPV6 */
- if (hapd->conf->nas_identifier &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_NAS_IDENTIFIER) &&
+ hapd->conf->nas_identifier &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
(u8 *) hapd->conf->nas_identifier,
os_strlen(hapd->conf->nas_identifier))) {
@@ -115,7 +125,9 @@
goto fail;
}
- if (sta &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_NAS_PORT) &&
+ sta &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
printf("Could not add NAS-Port\n");
goto fail;
@@ -123,7 +135,9 @@
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_CALLED_STATION_ID) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Called-Station-Id\n");
goto fail;
@@ -138,7 +152,10 @@
goto fail;
}
- if (!radius_msg_add_attr_int32(
+ if (!hostapd_config_get_radius_attr(
+ hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_NAS_PORT_TYPE) &&
+ !radius_msg_add_attr_int32(
msg, RADIUS_ATTR_NAS_PORT_TYPE,
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
printf("Could not add NAS-Port-Type\n");
@@ -149,7 +166,10 @@
radius_sta_rate(hapd, sta) / 2,
(radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
radius_mode_txt(hapd));
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+ if (!hostapd_config_get_radius_attr(
+ hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_CONNECT_INFO) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Connect-Info\n");
goto fail;
@@ -167,6 +187,26 @@
goto fail;
}
}
+
+ b = ieee802_1x_get_radius_cui(sta->eapol_sm);
+ if (b &&
+ !radius_msg_add_attr(msg,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ wpabuf_head(b), wpabuf_len(b))) {
+ wpa_printf(MSG_ERROR, "Could not add CUI");
+ goto fail;
+ }
+ }
+
+ for (attr = hapd->conf->radius_acct_req_attr; attr; attr = attr->next)
+ {
+ if (!radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val))) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS "
+ "attribute");
+ goto fail;
+ }
}
return msg;
@@ -259,8 +299,9 @@
hapd, sta);
msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
- if (msg)
- radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
+ if (msg &&
+ radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr) < 0)
+ radius_msg_free(msg);
sta->acct_session_started = 1;
}
@@ -358,9 +399,10 @@
goto fail;
}
- radius_client_send(hapd->radius, msg,
- stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
- sta->addr);
+ if (radius_client_send(hapd->radius, msg,
+ stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
+ sta->addr) < 0)
+ goto fail;
return;
fail:
@@ -463,7 +505,8 @@
return;
}
- radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
+ if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
+ radius_msg_free(msg);
}
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index b9f5994..811ffc1 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration helper functions
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -87,6 +87,8 @@
#ifdef CONFIG_IEEE80211R
bss->ft_over_ds = 1;
#endif /* CONFIG_IEEE80211R */
+
+ bss->radius_das_time_window = 300;
}
@@ -336,6 +338,30 @@
}
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type)
+{
+ for (; attr; attr = attr->next) {
+ if (attr->type == type)
+ return attr;
+ }
+ return NULL;
+}
+
+
+static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
+{
+ struct hostapd_radius_attr *prev;
+
+ while (attr) {
+ prev = attr;
+ attr = attr->next;
+ wpabuf_free(prev->val);
+ os_free(prev);
+ }
+}
+
+
static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
{
os_free(user->identity);
@@ -392,6 +418,8 @@
conf->radius->num_auth_servers);
hostapd_config_free_radius(conf->radius->acct_servers,
conf->radius->num_acct_servers);
+ hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
+ hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
os_free(conf->rsn_preauth_interfaces);
os_free(conf->ctrl_interface);
os_free(conf->ca_cert);
@@ -406,6 +434,7 @@
os_free(conf->radius_server_clients);
os_free(conf->test_socket);
os_free(conf->radius);
+ os_free(conf->radius_das_shared_secret);
hostapd_config_free_vlan(conf);
if (conf->ssid.dyn_vlan_keys) {
struct hostapd_ssid *ssid = &conf->ssid;
@@ -465,9 +494,13 @@
os_free(conf->model_description);
os_free(conf->model_url);
os_free(conf->upc);
+ wpabuf_free(conf->wps_nfc_dh_pubkey);
+ wpabuf_free(conf->wps_nfc_dh_privkey);
+ wpabuf_free(conf->wps_nfc_dev_pw);
#endif /* CONFIG_WPS */
os_free(conf->roaming_consortium);
+ os_free(conf->venue_name);
#ifdef CONFIG_RADIUS_TEST
os_free(conf->dump_msk_file);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 2ec25ad..13d5549 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration definitions and helpers functions
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -116,6 +116,12 @@
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
};
+struct hostapd_radius_attr {
+ u8 type;
+ struct wpabuf *val;
+ struct hostapd_radius_attr *next;
+};
+
#define NUM_TX_QUEUES 4
@@ -142,6 +148,12 @@
u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
};
+struct hostapd_venue_name {
+ u8 lang[3];
+ u8 name_len;
+ u8 name[252];
+};
+
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
@@ -171,6 +183,15 @@
char *nas_identifier;
struct hostapd_radius_servers *radius;
int acct_interim_interval;
+ int radius_request_cui;
+ struct hostapd_radius_attr *radius_auth_req_attr;
+ struct hostapd_radius_attr *radius_acct_req_attr;
+ int radius_das_port;
+ unsigned int radius_das_time_window;
+ int radius_das_require_event_timestamp;
+ struct hostapd_ip_addr radius_das_client_addr;
+ u8 *radius_das_shared_secret;
+ size_t radius_das_shared_secret_len;
struct hostapd_ssid ssid;
@@ -326,6 +347,10 @@
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ int wps_nfc_dev_pw_id;
+ struct wpabuf *wps_nfc_dh_pubkey;
+ struct wpabuf *wps_nfc_dh_privkey;
+ struct wpabuf *wps_nfc_dev_pw;
#endif /* CONFIG_WPS */
int pbc_in_m1;
@@ -343,6 +368,7 @@
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
int tdls;
int disable_11n;
+ int disable_11ac;
/* IEEE 802.11v */
int time_advertisement;
@@ -364,6 +390,13 @@
unsigned int roaming_consortium_count;
struct hostapd_roaming_consortium *roaming_consortium;
+ /* IEEE 802.11u - Venue Name duples */
+ unsigned int venue_name_count;
+ struct hostapd_venue_name *venue_name;
+
+ u16 gas_comeback_delay;
+ int gas_frag_limit;
+
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
#ifdef CONFIG_RADIUS_TEST
@@ -423,6 +456,9 @@
int ieee80211n;
int secondary_channel;
int require_ht;
+ u32 vht_capab;
+ int ieee80211ac;
+ u8 vht_oper_chwidth;
};
@@ -444,5 +480,7 @@
const struct hostapd_eap_user *
hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
size_t identity_len, int phase2);
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index d07cc6b..859b529 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -584,3 +584,15 @@
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
reason);
}
+
+
+int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
+ unsigned int wait, const u8 *dst, const u8 *data,
+ size_t len)
+{
+ if (hapd->driver == NULL || hapd->driver->send_action == NULL)
+ return 0;
+ return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
+ hapd->own_addr, hapd->own_addr, data,
+ len, 0);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 8038fa2..169c91b 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -86,6 +86,9 @@
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
const u8 *addr, int reason);
+int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
+ unsigned int wait, const u8 *dst, const u8 *data,
+ size_t len);
int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg);
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index b4252cf..933b158 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -289,10 +289,8 @@
ap->num_beacons++;
os_get_time(&now);
ap->last_beacon = now.sec;
- if (fi) {
- ap->ssi_signal = fi->ssi_signal;
+ if (fi)
ap->datarate = fi->datarate;
- }
if (!new_ap && ap != iface->ap_list) {
/* move AP entry into the beginning of the list so that the
@@ -320,7 +318,7 @@
#endif /* CONFIG_IEEE80211N */
if (set_beacon)
- ieee802_11_set_beacons(iface);
+ ieee802_11_update_beacons(iface);
}
@@ -375,7 +373,7 @@
}
if (set_beacon)
- ieee802_11_set_beacons(iface);
+ ieee802_11_update_beacons(iface);
}
diff --git a/src/ap/ap_list.h b/src/ap/ap_list.h
index 201f6ec..f0b4125 100644
--- a/src/ap/ap_list.h
+++ b/src/ap/ap_list.h
@@ -34,7 +34,6 @@
int channel;
int datarate; /* in 100 kbps */
- int ssi_signal;
int ht_support;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 4ea8684..0f29ccd 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -262,6 +262,11 @@
pos = hostapd_eid_adv_proto(hapd, pos);
pos = hostapd_eid_roaming_consortium(hapd, pos);
+#ifdef CONFIG_IEEE80211AC
+ pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_operation(hapd, pos);
+#endif /* CONFIG_IEEE80211AC */
+
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@@ -293,7 +298,8 @@
void handle_probe_req(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt, size_t len)
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int ssi_signal)
{
u8 *resp;
struct ieee802_11_elems elems;
@@ -311,7 +317,7 @@
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
mgmt->sa, mgmt->da, mgmt->bssid,
- ie, ie_len) > 0)
+ ie, ie_len, ssi_signal) > 0)
return;
if (!hapd->iconf->send_probe_response)
@@ -594,6 +600,11 @@
tailpos = hostapd_eid_adv_proto(hapd, tailpos);
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
+#ifdef CONFIG_IEEE80211AC
+ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+ tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+#endif /* CONFIG_IEEE80211AC */
+
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -682,6 +693,7 @@
!is_zero_ether_addr(hapd->conf->hessid))
params.hessid = hapd->conf->hessid;
params.access_network_type = hapd->conf->access_network_type;
+ params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
if (hostapd_drv_set_ap(hapd, ¶ms))
wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
@@ -699,4 +711,14 @@
ieee802_11_set_beacon(iface->bss[i]);
}
+
+/* only update beacons if started */
+void 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)
+ ieee802_11_set_beacon(iface->bss[i]);
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index a944f5f..37f10d2 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -19,8 +19,10 @@
struct ieee80211_mgmt;
void handle_probe_req(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt, size_t len);
+ 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);
#endif /* BEACON_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index d76b381..ab9c83e 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
@@ -17,6 +18,7 @@
#include "wps_hostapd.h"
#include "p2p_hostapd.h"
#include "ctrl_iface_ap.h"
+#include "ap_drv_ops.h"
static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
@@ -100,3 +102,170 @@
}
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
}
+
+
+#ifdef CONFIG_P2P_MANAGER
+static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
+ u8 minor_reason_code, const u8 *addr)
+{
+ struct ieee80211_mgmt *mgmt;
+ int ret;
+ u8 *pos;
+
+ if (hapd->driver->send_frame == NULL)
+ return -1;
+
+ mgmt = os_zalloc(sizeof(*mgmt) + 100);
+ if (mgmt == NULL)
+ return -1;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
+ " with minor reason code %u (stype=%u)",
+ MAC2STR(addr), minor_reason_code, stype);
+
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
+ 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);
+ if (stype == WLAN_FC_STYPE_DEAUTH) {
+ mgmt->u.deauth.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
+ } else {
+ mgmt->u.disassoc.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
+ }
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 + 3 + 1;
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = P2P_OUI_TYPE;
+
+ *pos++ = P2P_ATTR_MINOR_REASON_CODE;
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ *pos++ = minor_reason_code;
+
+ ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
+ pos - (u8 *) mgmt, 1);
+ os_free(mgmt);
+
+ return ret < 0 ? -1 : 0;
+}
+#endif /* CONFIG_P2P_MANAGER */
+
+
+int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ const char *pos;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
+ txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ pos = os_strstr(txtaddr, " test=");
+ if (pos) {
+ struct ieee80211_mgmt mgmt;
+ int encrypt;
+ if (hapd->driver->send_frame == NULL)
+ return -1;
+ pos += 6;
+ encrypt = atoi(pos);
+ os_memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DEAUTH);
+ 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.deauth.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ encrypt) < 0)
+ return -1;
+ return 0;
+ }
+
+#ifdef CONFIG_P2P_MANAGER
+ pos = os_strstr(txtaddr, " p2p=");
+ if (pos) {
+ return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
+ atoi(pos + 5), addr);
+ }
+#endif /* CONFIG_P2P_MANAGER */
+
+ hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ ap_sta_deauthenticate(hapd, sta,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ else if (addr[0] == 0xff)
+ hostapd_free_stas(hapd);
+
+ return 0;
+}
+
+
+int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ const char *pos;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
+ txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ pos = os_strstr(txtaddr, " test=");
+ if (pos) {
+ struct ieee80211_mgmt mgmt;
+ int encrypt;
+ if (hapd->driver->send_frame == NULL)
+ return -1;
+ pos += 6;
+ encrypt = atoi(pos);
+ os_memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DISASSOC);
+ 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.disassoc.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ encrypt) < 0)
+ return -1;
+ return 0;
+ }
+
+#ifdef CONFIG_P2P_MANAGER
+ pos = os_strstr(txtaddr, " p2p=");
+ if (pos) {
+ return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
+ atoi(pos + 5), addr);
+ }
+#endif /* CONFIG_P2P_MANAGER */
+
+ hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ ap_sta_disassociate(hapd, sta,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ else if (addr[0] == 0xff)
+ hostapd_free_stas(hapd);
+
+ return 0;
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index 0e4286d..e83f894 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -15,5 +15,9 @@
char *buf, size_t buflen);
int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
char *buf, size_t buflen);
+int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
+ const char *txtaddr);
+int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
+ const char *txtaddr);
#endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 820a903..cf06a4f 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -26,6 +26,7 @@
#include "wps_hostapd.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
+#include "hw_features.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -78,10 +79,19 @@
sta = ap_get_sta(hapd, addr);
if (sta) {
accounting_sta_stop(hapd, sta);
+
+ /*
+ * Make sure that the previously registered inactivity timer
+ * will not remove the STA immediately.
+ */
+ sta->timeout_next = STA_NULLFUNC;
} else {
sta = ap_sta_add(hapd, addr);
- if (sta == NULL)
+ if (sta == NULL) {
+ hostapd_drv_sta_disassoc(hapd, addr,
+ WLAN_REASON_DISASSOC_AP_BUSY);
return -1;
+ }
}
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
@@ -264,8 +274,36 @@
}
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+ int offset)
+{
+#ifdef NEED_AP_MLME
+ int channel;
+
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "driver had channel switch: "
+ "freq=%d, ht=%d, offset=%d", freq, ht, offset);
+
+ hapd->iface->freq = freq;
+
+ channel = hostapd_hw_get_channel(hapd, freq);
+ if (!channel) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING, "driver switched to "
+ "bad channel!");
+ return;
+ }
+
+ hapd->iconf->channel = channel;
+ hapd->iconf->ieee80211n = ht;
+ hapd->iconf->secondary_channel = offset;
+#endif /* NEED_AP_MLME */
+}
+
+
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
- const u8 *bssid, const u8 *ie, size_t ie_len)
+ const u8 *bssid, const u8 *ie, size_t ie_len,
+ int ssi_signal)
{
size_t i;
int ret = 0;
@@ -276,7 +314,8 @@
random_add_randomness(sa, ETH_ALEN);
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
- sa, da, bssid, ie, ie_len) > 0) {
+ sa, da, bssid, ie, ie_len,
+ ssi_signal) > 0) {
ret = 1;
break;
}
@@ -541,7 +580,8 @@
data->rx_probe_req.da,
data->rx_probe_req.bssid,
data->rx_probe_req.ie,
- data->rx_probe_req.ie_len);
+ data->rx_probe_req.ie_len,
+ data->rx_probe_req.ssi_signal);
break;
case EVENT_NEW_STA:
hostapd_event_new_sta(hapd, data->new_sta.addr);
@@ -578,6 +618,13 @@
hostapd_rx_action(hapd, &data->rx_action);
break;
#endif /* NEED_AP_MLME */
+ case EVENT_CH_SWITCH:
+ if (!data)
+ break;
+ hostapd_event_ch_switch(hapd, data->ch_switch.freq,
+ data->ch_switch.ht_enabled,
+ data->ch_switch.ch_offset);
+ break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
new file mode 100644
index 0000000..2177b02
--- /dev/null
+++ b/src/ap/gas_serv.c
@@ -0,0 +1,673 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "gas_serv.h"
+
+
+static struct gas_dialog_info *
+gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
+{
+ struct sta_info *sta;
+ struct gas_dialog_info *dia = NULL;
+ int i, j;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ /*
+ * We need a STA entry to be able to maintain state for
+ * the GAS query.
+ */
+ wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
+ "GAS query");
+ sta = ap_sta_add(hapd, addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
+ " for GAS query", MAC2STR(addr));
+ return NULL;
+ }
+ sta->flags |= WLAN_STA_GAS;
+ /*
+ * The default inactivity is 300 seconds. We don't need
+ * it to be that long.
+ */
+ ap_sta_session_timeout(hapd, sta, 5);
+ }
+
+ if (sta->gas_dialog == NULL) {
+ sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
+ sizeof(struct gas_dialog_info));
+ if (sta->gas_dialog == NULL)
+ return NULL;
+ }
+
+ for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
+ if (i == GAS_DIALOG_MAX)
+ i = 0;
+ if (sta->gas_dialog[i].valid)
+ continue;
+ dia = &sta->gas_dialog[i];
+ dia->valid = 1;
+ dia->index = i;
+ dia->dialog_token = dialog_token;
+ sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
+ return dia;
+ }
+
+ wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for "
+ MACSTR " dialog_token %u. Consider increasing "
+ "GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token);
+
+ return NULL;
+}
+
+
+struct gas_dialog_info *
+gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
+ u8 dialog_token)
+{
+ struct sta_info *sta;
+ int i;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
+ MAC2STR(addr));
+ return NULL;
+ }
+ for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) {
+ if (sta->gas_dialog[i].dialog_token != dialog_token ||
+ !sta->gas_dialog[i].valid)
+ continue;
+ return &sta->gas_dialog[i];
+ }
+ wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
+ MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
+ return NULL;
+}
+
+
+void gas_serv_dialog_clear(struct gas_dialog_info *dia)
+{
+ wpabuf_free(dia->sd_resp);
+ os_memset(dia, 0, sizeof(*dia));
+}
+
+
+static void gas_serv_free_dialogs(struct hostapd_data *hapd,
+ const u8 *sta_addr)
+{
+ struct sta_info *sta;
+ int i;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (sta == NULL || sta->gas_dialog == NULL)
+ return;
+
+ for (i = 0; i < GAS_DIALOG_MAX; i++) {
+ if (sta->gas_dialog[i].valid)
+ return;
+ }
+
+ os_free(sta->gas_dialog);
+ sta->gas_dialog = NULL;
+}
+
+
+static void anqp_add_capab_list(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ u8 *len;
+
+ len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
+ wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
+ if (hapd->conf->venue_name)
+ wpabuf_put_le16(buf, ANQP_VENUE_NAME);
+ if (hapd->conf->roaming_consortium)
+ wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
+ gas_anqp_set_element_len(buf, len);
+}
+
+
+static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+ if (hapd->conf->venue_name) {
+ u8 *len;
+ unsigned int i;
+ len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
+ wpabuf_put_u8(buf, hapd->conf->venue_group);
+ wpabuf_put_u8(buf, hapd->conf->venue_type);
+ for (i = 0; i < hapd->conf->venue_name_count; i++) {
+ struct hostapd_venue_name *vn;
+ vn = &hapd->conf->venue_name[i];
+ wpabuf_put_u8(buf, 3 + vn->name_len);
+ wpabuf_put_data(buf, vn->lang, 3);
+ wpabuf_put_data(buf, vn->name, vn->name_len);
+ }
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
+static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ unsigned int i;
+ u8 *len;
+
+ len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
+ for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
+ struct hostapd_roaming_consortium *rc;
+ rc = &hapd->conf->roaming_consortium[i];
+ wpabuf_put_u8(buf, rc->len);
+ wpabuf_put_data(buf, rc->oi, rc->len);
+ }
+ gas_anqp_set_element_len(buf, len);
+}
+
+
+static struct wpabuf *
+gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
+ unsigned int request,
+ struct gas_dialog_info *di)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(1400);
+ if (buf == NULL)
+ return NULL;
+
+ if (request & ANQP_REQ_CAPABILITY_LIST)
+ anqp_add_capab_list(hapd, buf);
+ if (request & ANQP_REQ_VENUE_NAME)
+ anqp_add_venue_name(hapd, buf);
+ if (request & ANQP_REQ_ROAMING_CONSORTIUM)
+ anqp_add_roaming_consortium(hapd, buf);
+
+ return buf;
+}
+
+
+static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
+{
+ struct gas_dialog_info *dia = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for "
+ "dialog token %d", dia->dialog_token);
+
+ gas_serv_dialog_clear(dia);
+}
+
+
+struct anqp_query_info {
+ unsigned int request;
+ unsigned int remote_request;
+ const void *param;
+ u32 param_arg;
+ u16 remote_delay;
+};
+
+
+static void set_anqp_req(unsigned int bit, const char *name, int local,
+ unsigned int remote, u16 remote_delay,
+ struct anqp_query_info *qi)
+{
+ qi->request |= bit;
+ if (local) {
+ wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
+ } else if (bit & remote) {
+ wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name);
+ qi->remote_request |= bit;
+ if (remote_delay > qi->remote_delay)
+ qi->remote_delay = remote_delay;
+ } else {
+ wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
+ }
+}
+
+
+static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
+ struct anqp_query_info *qi)
+{
+ switch (info_id) {
+ case ANQP_CAPABILITY_LIST:
+ set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0,
+ 0, qi);
+ break;
+ case ANQP_VENUE_NAME:
+ set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
+ hapd->conf->venue_name != NULL, 0, 0, qi);
+ break;
+ case ANQP_ROAMING_CONSORTIUM:
+ set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
+ hapd->conf->roaming_consortium != NULL, 0, 0, qi);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
+ info_id);
+ break;
+ }
+}
+
+
+static void rx_anqp_query_list(struct hostapd_data *hapd,
+ const u8 *pos, const u8 *end,
+ struct anqp_query_info *qi)
+{
+ wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
+ (unsigned int) (end - pos) / 2);
+
+ while (pos + 2 <= end) {
+ rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
+ pos += 2;
+ }
+}
+
+
+static void gas_serv_req_local_processing(struct hostapd_data *hapd,
+ const u8 *sa, u8 dialog_token,
+ struct anqp_query_info *qi)
+{
+ struct wpabuf *buf, *tx_buf;
+
+ buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL);
+ wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
+ buf);
+ if (!buf)
+ return;
+
+ if (wpabuf_len(buf) > hapd->gas_frag_limit ||
+ hapd->conf->gas_comeback_delay) {
+ struct gas_dialog_info *di;
+ u16 comeback_delay = 1;
+
+ if (hapd->conf->gas_comeback_delay) {
+ /* Testing - allow overriding of the delay value */
+ comeback_delay = hapd->conf->gas_comeback_delay;
+ }
+
+ wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
+ "initial response - use GAS comeback");
+ di = gas_dialog_create(hapd, sa, dialog_token);
+ if (!di) {
+ wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
+ "for " MACSTR " (dialog token %u)",
+ MAC2STR(sa), dialog_token);
+ wpabuf_free(buf);
+ return;
+ }
+ di->sd_resp = buf;
+ di->sd_resp_pos = 0;
+ tx_buf = gas_anqp_build_initial_resp_buf(
+ dialog_token, WLAN_STATUS_SUCCESS, comeback_delay,
+ NULL);
+ } else {
+ wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
+ tx_buf = gas_anqp_build_initial_resp_buf(
+ dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
+ wpabuf_free(buf);
+ }
+ if (!tx_buf)
+ return;
+
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ wpabuf_free(tx_buf);
+}
+
+
+static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
+ const u8 *sa,
+ const u8 *data, size_t len)
+{
+ const u8 *pos = data;
+ const u8 *end = data + len;
+ const u8 *next;
+ u8 dialog_token;
+ u16 slen;
+ struct anqp_query_info qi;
+ const u8 *adv_proto;
+
+ if (len < 1 + 2)
+ return;
+
+ os_memset(&qi, 0, sizeof(qi));
+
+ dialog_token = *pos++;
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
+ MAC2STR(sa), dialog_token);
+
+ if (*pos != WLAN_EID_ADV_PROTO) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "GAS: Unexpected IE in GAS Initial Request: %u", *pos);
+ return;
+ }
+ adv_proto = pos++;
+
+ slen = *pos++;
+ next = pos + slen;
+ if (next > end || slen < 2) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "GAS: Invalid IE in GAS Initial Request");
+ return;
+ }
+ pos++; /* skip QueryRespLenLimit and PAME-BI */
+
+ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
+ struct wpabuf *buf;
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "GAS: Unsupported GAS advertisement protocol id %u",
+ *pos);
+ if (sa[0] & 0x01)
+ return; /* Invalid source address - drop silently */
+ buf = gas_build_initial_resp(
+ dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
+ 0, 2 + slen + 2);
+ if (buf == NULL)
+ return;
+ wpabuf_put_data(buf, adv_proto, 2 + slen);
+ wpabuf_put_le16(buf, 0); /* Query Response Length */
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+ return;
+ }
+
+ pos = next;
+ /* Query Request */
+ if (pos + 2 > end)
+ return;
+ slen = WPA_GET_LE16(pos);
+ pos += 2;
+ if (pos + slen > end)
+ return;
+ end = pos + slen;
+
+ /* ANQP Query Request */
+ while (pos < end) {
+ u16 info_id, elen;
+
+ if (pos + 4 > end)
+ return;
+
+ info_id = WPA_GET_LE16(pos);
+ pos += 2;
+ elen = WPA_GET_LE16(pos);
+ pos += 2;
+
+ if (pos + elen > end) {
+ wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
+ return;
+ }
+
+ switch (info_id) {
+ case ANQP_QUERY_LIST:
+ rx_anqp_query_list(hapd, pos, pos + elen, &qi);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
+ "Request element %u", info_id);
+ break;
+ }
+
+ pos += elen;
+ }
+
+ gas_serv_req_local_processing(hapd, sa, dialog_token, &qi);
+}
+
+
+void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
+ struct gas_dialog_info *dialog)
+{
+ struct wpabuf *buf, *tx_buf;
+ u8 dialog_token = dialog->dialog_token;
+ size_t frag_len;
+
+ if (dialog->sd_resp == NULL) {
+ buf = gas_serv_build_gas_resp_payload(hapd,
+ dialog->all_requested,
+ dialog);
+ wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
+ buf);
+ if (!buf)
+ goto tx_gas_response_done;
+ dialog->sd_resp = buf;
+ dialog->sd_resp_pos = 0;
+ }
+ frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
+ if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
+ hapd->conf->gas_comeback_delay) {
+ u16 comeback_delay_tus = dialog->comeback_delay +
+ GAS_SERV_COMEBACK_DELAY_FUDGE;
+ u32 comeback_delay_secs, comeback_delay_usecs;
+
+ if (hapd->conf->gas_comeback_delay) {
+ /* Testing - allow overriding of the delay value */
+ comeback_delay_tus = hapd->conf->gas_comeback_delay;
+ }
+
+ wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
+ "%u) and comeback delay %u, "
+ "requesting comebacks", (unsigned int) frag_len,
+ (unsigned int) hapd->gas_frag_limit,
+ dialog->comeback_delay);
+ tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
+ WLAN_STATUS_SUCCESS,
+ comeback_delay_tus,
+ NULL);
+ if (tx_buf) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "GAS: Tx GAS Initial Resp (comeback = 10TU)");
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+ dst,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
+ }
+ wpabuf_free(tx_buf);
+
+ /* start a timer of 1.5 * comeback-delay */
+ comeback_delay_tus = comeback_delay_tus +
+ (comeback_delay_tus / 2);
+ comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
+ comeback_delay_usecs = (comeback_delay_tus * 1024) -
+ (comeback_delay_secs * 1000000);
+ eloop_register_timeout(comeback_delay_secs,
+ comeback_delay_usecs,
+ gas_serv_clear_cached_ies, dialog,
+ NULL);
+ goto tx_gas_response_done;
+ }
+
+ buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
+ dialog->sd_resp_pos, frag_len);
+ if (buf == NULL) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
+ "failed");
+ goto tx_gas_response_done;
+ }
+ tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
+ WLAN_STATUS_SUCCESS, 0, buf);
+ wpabuf_free(buf);
+ if (tx_buf == NULL)
+ goto tx_gas_response_done;
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
+ "Response (frag_id %d frag_len %d)",
+ dialog->sd_frag_id, (int) frag_len);
+ dialog->sd_frag_id++;
+
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
+ wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ wpabuf_free(tx_buf);
+tx_gas_response_done:
+ gas_serv_clear_cached_ies(dialog, NULL);
+}
+
+
+static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
+ const u8 *sa,
+ const u8 *data, size_t len)
+{
+ struct gas_dialog_info *dialog;
+ struct wpabuf *buf, *tx_buf;
+ u8 dialog_token;
+ size_t frag_len;
+ int more = 0;
+
+ wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
+ if (len < 1)
+ return;
+ dialog_token = *data;
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
+ dialog_token);
+
+ dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
+ if (!dialog) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
+ "response fragment for " MACSTR " dialog token %u",
+ MAC2STR(sa), dialog_token);
+
+ if (sa[0] & 0x01)
+ return; /* Invalid source address - drop silently */
+ tx_buf = gas_anqp_build_comeback_resp_buf(
+ dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
+ 0, NULL);
+ if (tx_buf == NULL)
+ return;
+ goto send_resp;
+ }
+
+ if (dialog->sd_resp == NULL) {
+ wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
+ dialog->requested, dialog->received);
+ if ((dialog->requested & dialog->received) !=
+ dialog->requested) {
+ wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
+ "from remote processing");
+ gas_serv_dialog_clear(dialog);
+ tx_buf = gas_anqp_build_comeback_resp_buf(
+ dialog_token,
+ WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
+ NULL);
+ if (tx_buf == NULL)
+ return;
+ goto send_resp;
+ }
+
+ buf = gas_serv_build_gas_resp_payload(hapd,
+ dialog->all_requested,
+ dialog);
+ wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
+ buf);
+ if (!buf)
+ goto rx_gas_comeback_req_done;
+ dialog->sd_resp = buf;
+ dialog->sd_resp_pos = 0;
+ }
+ frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
+ if (frag_len > hapd->gas_frag_limit) {
+ frag_len = hapd->gas_frag_limit;
+ more = 1;
+ }
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
+ (unsigned int) frag_len);
+ buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
+ dialog->sd_resp_pos, frag_len);
+ if (buf == NULL) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
+ "buffer");
+ goto rx_gas_comeback_req_done;
+ }
+ tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
+ WLAN_STATUS_SUCCESS,
+ dialog->sd_frag_id,
+ more, 0, buf);
+ wpabuf_free(buf);
+ if (tx_buf == NULL)
+ goto rx_gas_comeback_req_done;
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
+ "(frag_id %d more=%d frag_len=%d)",
+ dialog->sd_frag_id, more, (int) frag_len);
+ dialog->sd_frag_id++;
+ dialog->sd_resp_pos += frag_len;
+
+ if (more) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
+ "to be sent",
+ (int) (wpabuf_len(dialog->sd_resp) -
+ dialog->sd_resp_pos));
+ } else {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
+ "SD response sent");
+ gas_serv_dialog_clear(dialog);
+ gas_serv_free_dialogs(hapd, sa);
+ }
+
+send_resp:
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ wpabuf_free(tx_buf);
+ return;
+
+rx_gas_comeback_req_done:
+ gas_serv_clear_cached_ies(dialog, NULL);
+}
+
+
+static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
+ int freq)
+{
+ struct hostapd_data *hapd = ctx;
+ const struct ieee80211_mgmt *mgmt;
+ size_t hdr_len;
+ const u8 *sa, *data;
+
+ mgmt = (const struct ieee80211_mgmt *) buf;
+ hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+ if (hdr_len > len)
+ return;
+ if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+ return;
+ sa = mgmt->sa;
+ len -= hdr_len;
+ data = &mgmt->u.action.u.public_action.action;
+ switch (data[0]) {
+ case WLAN_PA_GAS_INITIAL_REQ:
+ gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1);
+ break;
+ case WLAN_PA_GAS_COMEBACK_REQ:
+ gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1);
+ break;
+ }
+}
+
+
+int gas_serv_init(struct hostapd_data *hapd)
+{
+ hapd->public_action_cb = gas_serv_rx_public_action;
+ hapd->public_action_cb_ctx = hapd;
+ hapd->gas_frag_limit = 1400;
+ if (hapd->conf->gas_frag_limit > 0)
+ hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
+ return 0;
+}
+
+
+void gas_serv_deinit(struct hostapd_data *hapd)
+{
+}
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
new file mode 100644
index 0000000..0e2eaf6
--- /dev/null
+++ b/src/ap/gas_serv.h
@@ -0,0 +1,49 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef GAS_SERV_H
+#define GAS_SERV_H
+
+#define ANQP_REQ_CAPABILITY_LIST \
+ (1 << (ANQP_CAPABILITY_LIST - ANQP_QUERY_LIST))
+#define ANQP_REQ_VENUE_NAME \
+ (1 << (ANQP_VENUE_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_ROAMING_CONSORTIUM \
+ (1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST))
+
+/* To account for latencies between hostapd and external ANQP processor */
+#define GAS_SERV_COMEBACK_DELAY_FUDGE 10
+#define GAS_SERV_MIN_COMEBACK_DELAY 100 /* in TU */
+
+struct gas_dialog_info {
+ u8 valid;
+ u8 index;
+ struct wpabuf *sd_resp; /* Fragmented response */
+ u8 dialog_token;
+ size_t sd_resp_pos; /* Offset in sd_resp */
+ u8 sd_frag_id;
+ u16 comeback_delay;
+
+ unsigned int requested;
+ unsigned int received;
+ unsigned int all_requested;
+};
+
+struct hostapd_data;
+
+void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
+ struct gas_dialog_info *dialog);
+struct gas_dialog_info *
+gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
+ u8 dialog_token);
+void gas_serv_dialog_clear(struct gas_dialog_info *dialog);
+
+int gas_serv_init(struct hostapd_data *hapd);
+void gas_serv_deinit(struct hostapd_data *hapd);
+
+#endif /* GAS_SERV_H */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index c5cbdf7..22c5e65 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "radius/radius_client.h"
+#include "radius/radius_das.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "authsrv.h"
@@ -30,15 +31,33 @@
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "p2p_hostapd.h"
+#include "gas_serv.h"
-static int hostapd_flush_old_stations(struct hostapd_data *hapd);
+static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
extern int wpa_debug_level;
+int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+ int (*cb)(struct hostapd_iface *iface,
+ void *ctx), void *ctx)
+{
+ size_t i;
+ int ret;
+
+ for (i = 0; i < interfaces->count; i++) {
+ ret = cb(interfaces->iface[i], ctx);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+
static void hostapd_reload_bss(struct hostapd_data *hapd)
{
#ifndef CONFIG_NO_RADIUS
@@ -105,7 +124,8 @@
* allow them to use the BSS anymore.
*/
for (j = 0; j < iface->num_bss; j++) {
- hostapd_flush_old_stations(iface->bss[j]);
+ hostapd_flush_old_stations(iface->bss[j],
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_broadcast_wep_clear(iface->bss[j]);
#ifndef CONFIG_NO_RADIUS
@@ -210,21 +230,9 @@
return errors;
}
-/**
- * hostapd_cleanup - Per-BSS cleanup (deinitialization)
- * @hapd: Pointer to BSS data
- *
- * This function is used to free all per-BSS data structures and resources.
- * This gets called in a loop for each BSS between calls to
- * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
- * is deinitialized. Most of the modules that are initialized in
- * hostapd_setup_bss() are deinitialized here.
- */
-static void hostapd_cleanup(struct hostapd_data *hapd)
-{
- if (hapd->iface->ctrl_iface_deinit)
- hapd->iface->ctrl_iface_deinit(hapd);
+static void hostapd_free_hapd_data(struct hostapd_data *hapd)
+{
iapp_deinit(hapd->iapp);
hapd->iapp = NULL;
accounting_deinit(hapd);
@@ -234,6 +242,8 @@
#ifndef CONFIG_NO_RADIUS
radius_client_deinit(hapd->radius);
hapd->radius = NULL;
+ radius_das_deinit(hapd->radius_das);
+ hapd->radius_das = NULL;
#endif /* CONFIG_NO_RADIUS */
hostapd_deinit_wps(hapd);
@@ -257,6 +267,28 @@
#endif /* CONFIG_P2P */
wpabuf_free(hapd->time_adv);
+
+#ifdef CONFIG_INTERWORKING
+ gas_serv_deinit(hapd);
+#endif /* CONFIG_INTERWORKING */
+}
+
+
+/**
+ * hostapd_cleanup - Per-BSS cleanup (deinitialization)
+ * @hapd: Pointer to BSS data
+ *
+ * This function is used to free all per-BSS data structures and resources.
+ * This gets called in a loop for each BSS between calls to
+ * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
+ * is deinitialized. Most of the modules that are initialized in
+ * hostapd_setup_bss() are deinitialized here.
+ */
+static void hostapd_cleanup(struct hostapd_data *hapd)
+{
+ if (hapd->iface->ctrl_iface_deinit)
+ hapd->iface->ctrl_iface_deinit(hapd);
+ hostapd_free_hapd_data(hapd);
}
@@ -272,6 +304,18 @@
}
+static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+{
+ hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+ iface->hw_features = NULL;
+ os_free(iface->current_rates);
+ iface->current_rates = NULL;
+ os_free(iface->basic_rates);
+ iface->basic_rates = NULL;
+ ap_list_deinit(iface);
+}
+
+
/**
* hostapd_cleanup_iface - Complete per-interface cleanup
* @iface: Pointer to interface data
@@ -281,13 +325,7 @@
*/
static void hostapd_cleanup_iface(struct hostapd_iface *iface)
{
- hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
- iface->hw_features = NULL;
- os_free(iface->current_rates);
- iface->current_rates = NULL;
- os_free(iface->basic_rates);
- iface->basic_rates = NULL;
- ap_list_deinit(iface);
+ hostapd_cleanup_iface_partial(iface);
hostapd_config_free(iface->conf);
iface->conf = NULL;
@@ -297,6 +335,15 @@
}
+static void hostapd_clear_wep(struct hostapd_data *hapd)
+{
+ if (hapd->drv_priv) {
+ hostapd_set_privacy(hapd, 0);
+ hostapd_broadcast_wep_clear(hapd);
+ }
+}
+
+
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
{
int i;
@@ -333,7 +380,7 @@
}
-static int hostapd_flush_old_stations(struct hostapd_data *hapd)
+static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
{
int ret = 0;
u8 addr[ETH_ALEN];
@@ -349,7 +396,7 @@
}
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
os_memset(addr, 0xff, ETH_ALEN);
- hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ hostapd_drv_sta_deauth(hapd, addr, reason);
hostapd_free_stas(hapd);
return ret;
@@ -464,6 +511,86 @@
}
+#ifndef CONFIG_NO_RADIUS
+
+static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
+ struct radius_das_attrs *attr)
+{
+ /* TODO */
+ return 0;
+}
+
+
+static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
+ struct radius_das_attrs *attr)
+{
+ struct sta_info *sta = NULL;
+ char buf[128];
+
+ if (attr->sta_addr)
+ sta = ap_get_sta(hapd, attr->sta_addr);
+
+ if (sta == NULL && attr->acct_session_id &&
+ attr->acct_session_id_len == 17) {
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ os_snprintf(buf, sizeof(buf), "%08X-%08X",
+ sta->acct_session_id_hi,
+ sta->acct_session_id_lo);
+ if (os_memcmp(attr->acct_session_id, buf, 17) == 0)
+ break;
+ }
+ }
+
+ if (sta == NULL && attr->cui) {
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ struct wpabuf *cui;
+ cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
+ if (cui && wpabuf_len(cui) == attr->cui_len &&
+ os_memcmp(wpabuf_head(cui), attr->cui,
+ attr->cui_len) == 0)
+ break;
+ }
+ }
+
+ if (sta == NULL && attr->user_name) {
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ u8 *identity;
+ size_t identity_len;
+ identity = ieee802_1x_get_identity(sta->eapol_sm,
+ &identity_len);
+ if (identity &&
+ identity_len == attr->user_name_len &&
+ os_memcmp(identity, attr->user_name, identity_len)
+ == 0)
+ break;
+ }
+ }
+
+ return sta;
+}
+
+
+static enum radius_das_res
+hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ if (hostapd_das_nas_mismatch(hapd, attr))
+ return RADIUS_DAS_NAS_MISMATCH;
+
+ sta = hostapd_das_find_sta(hapd, attr);
+ if (sta == NULL)
+ return RADIUS_DAS_SESSION_NOT_FOUND;
+
+ hostapd_drv_sta_deauth(hapd, sta->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+ return RADIUS_DAS_SUCCESS;
+}
+
+#endif /* CONFIG_NO_RADIUS */
/**
@@ -519,7 +646,7 @@
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n;
- hostapd_flush_old_stations(hapd);
+ hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd);
@@ -583,6 +710,27 @@
wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
return -1;
}
+
+ if (hapd->conf->radius_das_port) {
+ struct radius_das_conf das_conf;
+ os_memset(&das_conf, 0, sizeof(das_conf));
+ das_conf.port = hapd->conf->radius_das_port;
+ das_conf.shared_secret = hapd->conf->radius_das_shared_secret;
+ das_conf.shared_secret_len =
+ hapd->conf->radius_das_shared_secret_len;
+ das_conf.client_addr = &hapd->conf->radius_das_client_addr;
+ das_conf.time_window = hapd->conf->radius_das_time_window;
+ das_conf.require_event_timestamp =
+ hapd->conf->radius_das_require_event_timestamp;
+ das_conf.ctx = hapd;
+ das_conf.disconnect = hostapd_das_disconnect;
+ hapd->radius_das = radius_das_init(&das_conf);
+ if (hapd->radius_das == NULL) {
+ wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
+ "failed.");
+ return -1;
+ }
+ }
#endif /* CONFIG_NO_RADIUS */
if (hostapd_acl_init(hapd)) {
@@ -615,6 +763,13 @@
return -1;
}
+#ifdef CONFIG_INTERWORKING
+ if (gas_serv_init(hapd)) {
+ wpa_printf(MSG_ERROR, "GAS server initialization failed");
+ return -1;
+ }
+#endif /* CONFIG_INTERWORKING */
+
if (hapd->iface->ctrl_iface_init &&
hapd->iface->ctrl_iface_init(hapd)) {
wpa_printf(MSG_ERROR, "Failed to setup control interface");
@@ -857,6 +1012,7 @@
hapd->conf = bss;
hapd->iface = hapd_iface;
hapd->driver = hapd->iconf->driver;
+ hapd->ctrl_sock = -1;
return hapd;
}
@@ -873,7 +1029,8 @@
for (j = 0; j < iface->num_bss; j++) {
struct hostapd_data *hapd = iface->bss[j];
hostapd_free_stas(hapd);
- hostapd_flush_old_stations(hapd);
+ hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+ hostapd_clear_wep(hapd);
hostapd_cleanup(hapd);
}
}
@@ -937,4 +1094,12 @@
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
} else
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
+
+ wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - ap_max_inactivity)",
+ __func__, MAC2STR(sta->addr),
+ hapd->conf->ap_max_inactivity);
+ eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+ eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+ ap_handle_timer, hapd, sta);
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index bc28805..f7ed311 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -15,7 +15,6 @@
struct wpa_ctrl_dst;
struct radius_server_data;
struct upnp_wps_device_sm;
-struct hapd_interfaces;
struct hostapd_data;
struct sta_info;
struct hostap_sta_driver_data;
@@ -24,9 +23,15 @@
enum wps_event;
union wps_event_data;
+struct hapd_interfaces {
+ size_t count;
+ struct hostapd_iface **iface;
+};
+
+
struct hostapd_probereq_cb {
int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
- const u8 *ie, size_t ie_len);
+ const u8 *ie, size_t ie_len, int ssi_signal);
void *ctx;
};
@@ -40,7 +45,7 @@
struct hostapd_frame_info {
u32 channel;
u32 datarate;
- u32 ssi_signal;
+ int ssi_signal; /* dBm */
};
@@ -80,6 +85,7 @@
struct radius_client_data *radius;
u32 acct_session_id_hi, acct_session_id_lo;
+ struct radius_das_data *radius_das;
struct iapp_data *iapp;
@@ -164,6 +170,9 @@
int noa_start;
int noa_duration;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+ size_t gas_frag_limit;
+#endif /* CONFIG_INTERWORKING */
};
@@ -242,6 +251,9 @@
};
/* hostapd.c */
+int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+ int (*cb)(struct hostapd_iface *iface,
+ void *ctx), void *ctx);
int hostapd_reload_config(struct hostapd_iface *iface);
struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
@@ -258,7 +270,8 @@
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
const u8 *da, const u8 *bssid,
- const u8 *ie, size_t ie_len),
+ const u8 *ie, size_t ie_len,
+ int ssi_signal),
void *ctx);
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
@@ -268,6 +281,9 @@
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
- const u8 *bssid, const u8 *ie, size_t ie_len);
+ const u8 *bssid, const u8 *ie, size_t ie_len,
+ int ssi_signal);
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+ int offset);
#endif /* HOSTAPD_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 8c6fef2..76c4211 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -2,7 +2,7 @@
* hostapd / Hardware feature query and different modes
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
+ * 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
@@ -416,7 +416,7 @@
int res;
/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
- * allowed per IEEE 802.11n/D7.0, 11.14.3.2 */
+ * allowed per IEEE Std 802.11-2012, 10.15.3.2 */
iface->scan_cb = NULL;
@@ -447,6 +447,46 @@
}
+static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
+ struct wpa_driver_scan_params *params)
+{
+ /* Scan only the affected frequency range */
+ int pri_freq, sec_freq;
+ int affected_start, affected_end;
+ int i, pos;
+ struct hostapd_hw_modes *mode;
+
+ if (iface->current_mode == NULL)
+ return;
+
+ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+ if (iface->conf->secondary_channel > 0)
+ sec_freq = pri_freq + 20;
+ else
+ sec_freq = pri_freq - 20;
+ affected_start = (pri_freq + sec_freq) / 2 - 25;
+ affected_end = (pri_freq + sec_freq) / 2 + 25;
+ wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+ affected_start, affected_end);
+
+ mode = iface->current_mode;
+ params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+ if (params->freqs == NULL)
+ return;
+ pos = 0;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ if (chan->freq < affected_start ||
+ chan->freq > affected_end)
+ continue;
+ params->freqs[pos++] = chan->freq;
+ }
+}
+
+
static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
@@ -457,12 +497,15 @@
wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
"40 MHz channel");
os_memset(¶ms, 0, sizeof(params));
- /* TODO: scan only the needed frequency */
+ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ ieee80211n_scan_channels_2g4(iface, ¶ms);
if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) {
wpa_printf(MSG_ERROR, "Failed to request a scan of "
"neighboring BSSes");
+ os_free(params.freqs);
return -1;
}
+ os_free(params.freqs);
iface->scan_cb = ieee80211n_check_scan;
return 1;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 9c931ca..3996c90 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -876,6 +876,7 @@
#endif /* CONFIG_IEEE80211N */
p = hostapd_eid_ext_capab(hapd, p);
+ p = hostapd_eid_bss_max_idle_period(hapd, p);
if (sta->flags & WLAN_STA_WMM)
p = hostapd_eid_wmm(hapd, p);
@@ -1392,7 +1393,7 @@
if (stype == WLAN_FC_STYPE_PROBE_REQ) {
- handle_probe_req(hapd, mgmt, len);
+ handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
return;
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index d30e90f..9993bee 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -45,6 +45,8 @@
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *trans_id);
@@ -72,5 +74,6 @@
u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
int hostapd_update_time_adv(struct hostapd_data *hapd);
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 109c4bc..0c4c5f3 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -193,7 +193,8 @@
goto fail;
}
- radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
+ if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
+ goto fail;
return 0;
fail:
@@ -492,7 +493,7 @@
}
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
- cache->psk == NULL)
+ !cache->has_psk)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 0935cd5..b3fdf3d 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -397,3 +397,31 @@
return 0;
}
+
+
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+
+#ifdef CONFIG_WNM
+ if (hapd->conf->ap_max_inactivity > 0) {
+ unsigned int val;
+ *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
+ *pos++ = 3;
+ val = hapd->conf->ap_max_inactivity;
+ if (val > 68000)
+ val = 68000;
+ val *= 1000;
+ val /= 1024;
+ if (val == 0)
+ val = 1;
+ if (val > 65535)
+ val = 65535;
+ WPA_PUT_LE16(pos, val);
+ pos += 2;
+ *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
+ }
+#endif /* CONFIG_WNM */
+
+ return pos;
+}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
new file mode 100644
index 0000000..3ad33c8
--- /dev/null
+++ b/src/ap/ieee802_11_vht.c
@@ -0,0 +1,72 @@
+/*
+ * hostapd / IEEE 802.11ac VHT
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of BSD license
+ *
+ * See README and COPYING 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"
+#include "beacon.h"
+#include "ieee802_11.h"
+
+
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_vht_capabilities *cap;
+ u8 *pos = eid;
+
+ if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
+ hapd->conf->disable_11ac)
+ return eid;
+
+ *pos++ = WLAN_EID_VHT_CAP;
+ *pos++ = sizeof(*cap);
+
+ cap = (struct ieee80211_vht_capabilities *) pos;
+ os_memset(cap, 0, sizeof(*cap));
+ cap->vht_capabilities_info = host_to_le32(
+ hapd->iface->current_mode->vht_capab);
+
+ /* Supported MCS set comes from hw */
+ os_memcpy(cap->vht_supported_mcs_set,
+ hapd->iface->current_mode->vht_mcs_set, 8);
+
+ pos += sizeof(*cap);
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_vht_operation *oper;
+ u8 *pos = eid;
+
+ if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
+ return eid;
+
+ *pos++ = WLAN_EID_VHT_OPERATION;
+ *pos++ = sizeof(*oper);
+
+ oper = (struct ieee80211_vht_operation *) pos;
+ os_memset(oper, 0, sizeof(*oper));
+
+ oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
+
+ /* VHT Basic MCS set comes from hw */
+ /* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
+ oper->vht_basic_mcs_set = 0xfffc;
+ pos += sizeof(*oper);
+
+ return pos;
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index a329777..dd0df1d 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -416,6 +416,7 @@
struct radius_msg *msg;
char buf[128];
struct eapol_state_machine *sm = sta->eapol_sm;
+ struct hostapd_radius_attr *attr;
if (sm == NULL)
return;
@@ -442,7 +443,9 @@
goto fail;
}
- if (hapd->conf->own_ip_addr.af == AF_INET &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_NAS_IP_ADDRESS) &&
+ hapd->conf->own_ip_addr.af == AF_INET &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
printf("Could not add NAS-IP-Address\n");
@@ -450,7 +453,9 @@
}
#ifdef CONFIG_IPV6
- if (hapd->conf->own_ip_addr.af == AF_INET6 &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
+ hapd->conf->own_ip_addr.af == AF_INET6 &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
printf("Could not add NAS-IPv6-Address\n");
@@ -458,7 +463,9 @@
}
#endif /* CONFIG_IPV6 */
- if (hapd->conf->nas_identifier &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_NAS_IDENTIFIER) &&
+ hapd->conf->nas_identifier &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
(u8 *) hapd->conf->nas_identifier,
os_strlen(hapd->conf->nas_identifier))) {
@@ -466,7 +473,9 @@
goto fail;
}
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_NAS_PORT) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
printf("Could not add NAS-Port\n");
goto fail;
}
@@ -474,7 +483,9 @@
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
buf[sizeof(buf) - 1] = '\0';
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_CALLED_STATION_ID) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Called-Station-Id\n");
goto fail;
@@ -492,12 +503,16 @@
/* TODO: should probably check MTU from driver config; 2304 is max for
* IEEE 802.11, but use 1400 to avoid problems with too large packets
*/
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_FRAMED_MTU) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
printf("Could not add Framed-MTU\n");
goto fail;
}
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_NAS_PORT_TYPE) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
printf("Could not add NAS-Port-Type\n");
goto fail;
@@ -513,7 +528,9 @@
radius_mode_txt(hapd));
buf[sizeof(buf) - 1] = '\0';
}
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_CONNECT_INFO) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Connect-Info\n");
goto fail;
@@ -541,6 +558,36 @@
}
}
+ if (hapd->conf->radius_request_cui) {
+ const u8 *cui;
+ size_t cui_len;
+ /* Add previously learned CUI or nul CUI to request CUI */
+ if (sm->radius_cui) {
+ cui = wpabuf_head(sm->radius_cui);
+ cui_len = wpabuf_len(sm->radius_cui);
+ } else {
+ cui = (const u8 *) "\0";
+ cui_len = 1;
+ }
+ if (!radius_msg_add_attr(msg,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ cui, cui_len)) {
+ wpa_printf(MSG_ERROR, "Could not add CUI");
+ goto fail;
+ }
+ }
+
+ for (attr = hapd->conf->radius_auth_req_attr; attr; attr = attr->next)
+ {
+ if (!radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val))) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS "
+ "attribute");
+ goto fail;
+ }
+ }
+
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
goto fail;
@@ -861,12 +908,22 @@
if (!force_1x && !hapd->conf->ieee802_1x) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
"802.1X not enabled or forced for WPS");
+ /*
+ * Clear any possible EAPOL authenticator state to support
+ * reassociation change from WPS to PSK.
+ */
+ ieee802_1x_free_station(sta);
return;
}
key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK");
+ /*
+ * Clear any possible EAPOL authenticator state to support
+ * reassociation change from WPA-EAP to PSK.
+ */
+ ieee802_1x_free_station(sta);
return;
}
@@ -968,6 +1025,7 @@
#ifndef CONFIG_NO_RADIUS
radius_msg_free(sm->last_recv_radius);
radius_free_class(&sm->radius_class);
+ wpabuf_free(sm->radius_cui);
#endif /* CONFIG_NO_RADIUS */
os_free(sm->identity);
@@ -1189,6 +1247,32 @@
}
+/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */
+static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct radius_msg *msg)
+{
+ struct eapol_state_machine *sm = sta->eapol_sm;
+ struct wpabuf *cui;
+ u8 *buf;
+ size_t len;
+
+ if (sm == NULL)
+ return;
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ &buf, &len, NULL) < 0)
+ return;
+
+ cui = wpabuf_alloc_copy(buf, len);
+ if (cui == NULL)
+ return;
+
+ wpabuf_free(sm->radius_cui);
+ sm->radius_cui = cui;
+}
+
+
struct sta_id_search {
u8 identifier;
struct eapol_state_machine *sm;
@@ -1348,6 +1432,7 @@
shared_secret_len);
ieee802_1x_store_radius_class(hapd, sta, msg);
ieee802_1x_update_sta_identity(hapd, sta, msg);
+ ieee802_1x_update_sta_cui(hapd, sta, msg);
if (sm->eap_if->eapKeyAvailable &&
wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
session_timeout_set ?
@@ -1865,6 +1950,14 @@
}
+struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
+{
+ if (sm == NULL)
+ return NULL;
+ return sm->radius_cui;
+}
+
+
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
{
*len = 0;
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 58f6084..f9b05ca 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -67,6 +67,7 @@
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
int idx);
+struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled);
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 9eb4840..ba2c033 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -1,6 +1,6 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -40,6 +40,7 @@
if (entry == NULL)
return;
os_free(entry->identity);
+ wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS
radius_free_class(&entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
@@ -136,6 +137,9 @@
}
}
+ if (eapol->radius_cui)
+ entry->cui = wpabuf_dup(eapol->radius_cui);
+
#ifndef CONFIG_NO_RADIUS
radius_copy_class(&entry->radius_class, &eapol->radius_class);
#endif /* CONFIG_NO_RADIUS */
@@ -163,6 +167,11 @@
eapol->identity, eapol->identity_len);
}
+ if (entry->cui) {
+ wpabuf_free(eapol->radius_cui);
+ eapol->radius_cui = wpabuf_dup(entry->cui);
+ }
+
#ifndef CONFIG_NO_RADIUS
radius_free_class(&eapol->radius_class);
radius_copy_class(&eapol->radius_class, &entry->radius_class);
@@ -299,6 +308,8 @@
old_entry->identity_len);
}
}
+ if (old_entry->cui)
+ entry->cui = wpabuf_dup(old_entry->cui);
#ifndef CONFIG_NO_RADIUS
radius_copy_class(&entry->radius_class, &old_entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index 74b73c4..d473f3f 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -1,6 +1,6 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -25,6 +25,7 @@
u8 *identity;
size_t identity_len;
+ struct wpabuf *cui;
struct radius_class_data radius_class;
u8 eap_type_authsrv;
int vlan_id;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index afabdaa..95b701c 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -28,6 +28,7 @@
#include "vlan_init.h"
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
+#include "gas_serv.h"
#include "sta_info.h"
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
@@ -194,6 +195,8 @@
if (set_beacon)
ieee802_11_set_beacons(hapd->iface);
+ wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
+ __func__, MAC2STR(sta->addr));
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
@@ -218,6 +221,15 @@
p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+ if (sta->gas_dialog) {
+ int i;
+ for (i = 0; i < GAS_DIALOG_MAX; i++)
+ gas_serv_dialog_clear(&sta->gas_dialog[i]);
+ os_free(sta->gas_dialog);
+ }
+#endif /* CONFIG_INTERWORKING */
+
wpabuf_free(sta->wps_ie);
wpabuf_free(sta->p2p_ie);
@@ -262,6 +274,9 @@
struct sta_info *sta = timeout_ctx;
unsigned long next_time = 0;
+ wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
+ __func__, MAC2STR(sta->addr), sta->flags,
+ sta->timeout_next);
if (sta->timeout_next == STA_REMOVE) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
@@ -274,6 +289,12 @@
(sta->timeout_next == STA_NULLFUNC ||
sta->timeout_next == STA_DISASSOC)) {
int inactive_sec;
+ /*
+ * Add random value to timeout so that we don't end up bouncing
+ * all stations at the same time if we have lots of associated
+ * stations that are idle (but keep re-associating).
+ */
+ int fuzz = os_random() % 20;
inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
if (inactive_sec == -1) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
@@ -285,7 +306,7 @@
* Anyway, try again after the next inactivity timeout,
* but do not disconnect the station now.
*/
- next_time = hapd->conf->ap_max_inactivity;
+ next_time = hapd->conf->ap_max_inactivity + fuzz;
} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
sta->flags & WLAN_STA_ASSOC) {
/* station activity detected; reset timeout state */
@@ -293,7 +314,7 @@
"Station " MACSTR " has been active %is ago",
MAC2STR(sta->addr), inactive_sec);
sta->timeout_next = STA_NULLFUNC;
- next_time = hapd->conf->ap_max_inactivity -
+ next_time = hapd->conf->ap_max_inactivity + fuzz -
inactive_sec;
} else {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
@@ -320,6 +341,9 @@
}
if (next_time) {
+ wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+ "for " MACSTR " (%lu seconds)",
+ __func__, MAC2STR(sta->addr), next_time);
eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
sta);
return;
@@ -353,6 +377,9 @@
switch (sta->timeout_next) {
case STA_NULLFUNC:
sta->timeout_next = STA_DISASSOC;
+ wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)",
+ __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY);
eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
hapd, sta);
break;
@@ -369,6 +396,9 @@
HOSTAPD_LEVEL_INFO, "disassociated due to "
"inactivity");
sta->timeout_next = STA_DEAUTH;
+ wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
+ __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
hapd, sta);
mlme_disassociate_indication(
@@ -397,8 +427,14 @@
struct sta_info *sta = timeout_ctx;
u8 addr[ETH_ALEN];
- if (!(sta->flags & WLAN_STA_AUTH))
+ if (!(sta->flags & WLAN_STA_AUTH)) {
+ if (sta->flags & WLAN_STA_GAS) {
+ wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
+ "entry " MACSTR, MAC2STR(sta->addr));
+ ap_free_sta(hapd, sta);
+ }
return;
+ }
mlme_deauthenticate_indication(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -455,6 +491,10 @@
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
/* initialize STA info data */
+ wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - ap_max_inactivity)",
+ __func__, MAC2STR(addr),
+ hapd->conf->ap_max_inactivity);
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
os_memcpy(sta->addr, addr, ETH_ALEN);
@@ -528,6 +568,11 @@
sta->flags &= ~WLAN_STA_ASSOC;
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_DEAUTH;
+ wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - "
+ "AP_MAX_INACTIVITY_AFTER_DISASSOC)",
+ __func__, MAC2STR(sta->addr),
+ AP_MAX_INACTIVITY_AFTER_DISASSOC);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
ap_handle_timer, hapd, sta);
@@ -561,6 +606,11 @@
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_REMOVE;
+ wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - "
+ "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
+ __func__, MAC2STR(sta->addr),
+ AP_MAX_INACTIVITY_AFTER_DEAUTH);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
ap_handle_timer, hapd, sta);
@@ -576,6 +626,23 @@
}
+#ifdef CONFIG_WPS
+int ap_sta_wps_cancel(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx)
+{
+ if (sta && (sta->flags & WLAN_STA_WPS)) {
+ ap_sta_deauthenticate(hapd, sta,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
+ __func__, MAC2STR(sta->addr));
+ return 1;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_WPS */
+
+
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid)
{
@@ -778,11 +845,20 @@
int authorized)
{
const u8 *dev_addr = NULL;
+#ifdef CONFIG_P2P
+ u8 addr[ETH_ALEN];
+#endif /* CONFIG_P2P */
+
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
return;
#ifdef CONFIG_P2P
- dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
+ if (hapd->p2p_group == NULL) {
+ if (sta->p2p_ie != NULL &&
+ p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0)
+ dev_addr = addr;
+ } else
+ dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
#endif /* CONFIG_P2P */
if (authorized) {
@@ -848,6 +924,11 @@
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - "
+ "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
+ __func__, MAC2STR(sta->addr),
+ AP_MAX_INACTIVITY_AFTER_DEAUTH);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
ap_handle_timer, hapd, sta);
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 60b3a7b..cef428d 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -27,6 +27,7 @@
#define WLAN_STA_WDS BIT(14)
#define WLAN_STA_ASSOC_REQ_OK BIT(15)
#define WLAN_STA_WPS2 BIT(16)
+#define WLAN_STA_GAS BIT(17)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -107,6 +108,12 @@
struct os_time sa_query_start;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_INTERWORKING
+#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
+ struct gas_dialog_info *gas_dialog;
+ u8 gas_dialog_next;
+#endif /* CONFIG_INTERWORKING */
+
struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
};
@@ -137,7 +144,6 @@
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
-void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
void hostapd_free_stas(struct hostapd_data *hapd);
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
@@ -149,6 +155,10 @@
u16 reason);
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason);
+#ifdef CONFIG_WPS
+int ap_sta_wps_cancel(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx);
+#endif /* CONFIG_WPS */
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid);
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c
index 60088ee..dd5aa68 100644
--- a/src/ap/tkip_countermeasures.c
+++ b/src/ap/tkip_countermeasures.c
@@ -1,6 +1,6 @@
/*
* hostapd / TKIP countermeasures
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "radius/radius.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_mlme.h"
@@ -44,12 +45,17 @@
eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
hapd, NULL);
- for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
+ while ((sta = hapd->sta_list)) {
+ sta->acct_terminate_cause =
+ RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET;
+ if (sta->flags & WLAN_STA_AUTH) {
+ mlme_deauthenticate_indication(
+ hapd, sta,
+ WLAN_REASON_MICHAEL_MIC_FAILURE);
+ }
hostapd_drv_sta_deauth(hapd, sta->addr,
WLAN_REASON_MICHAEL_MIC_FAILURE);
- ap_sta_set_authorized(hapd, sta, 0);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
- hostapd_drv_sta_remove(hapd, sta->addr);
+ ap_free_sta(hapd, sta);
}
}
diff --git a/src/ap/utils.c b/src/ap/utils.c
index 36c1182..3e9fc08 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -17,7 +17,8 @@
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
const u8 *da, const u8 *bssid,
- const u8 *ie, size_t ie_len),
+ const u8 *ie, size_t ie_len,
+ int ssi_signal),
void *ctx)
{
struct hostapd_probereq_cb *n;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index d1b9b4d..1d942a4 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1641,10 +1641,23 @@
wpa_group_ensure_init(sm->wpa_auth, sm->group);
- os_memcpy(sm->ANonce, sm->group->Counter, WPA_NONCE_LEN);
+ /*
+ * Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
+ * ambiguous. The Authenticator state machine uses a counter that is
+ * incremented by one for each 4-way handshake. However, the security
+ * analysis of 4-way handshake points out that unpredictable nonces
+ * help in preventing precomputation attacks. Instead of the state
+ * machine definition, use an unpredictable nonce value here to provide
+ * stronger protection against potential precomputation attacks.
+ */
+ if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+ wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
+ "ANonce.");
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+ return;
+ }
wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
WPA_NONCE_LEN);
- inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
sm->ReAuthenticationRequest = FALSE;
/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
* logical place than INITIALIZE since AUTHENTICATION2 can be
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 8999217..07ce06c 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1,6 +1,6 @@
/*
* hostapd / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,8 @@
#include "utils/eloop.h"
#include "utils/uuid.h"
#include "crypto/dh_groups.h"
+#include "crypto/dh_group5.h"
+#include "crypto/random.h"
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -20,6 +22,7 @@
#include "wps/wps.h"
#include "wps/wps_defs.h"
#include "wps/wps_dev_attr.h"
+#include "wps/wps_attr_parse.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
@@ -37,7 +40,8 @@
static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
const u8 *bssid,
- const u8 *ie, size_t ie_len);
+ const u8 *ie, size_t ie_len,
+ int ssi_signal);
static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
@@ -183,19 +187,23 @@
struct wps_stop_reg_data {
struct hostapd_data *current_hapd;
const u8 *uuid_e;
+ const u8 *dev_pw;
+ size_t dev_pw_len;
};
static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx)
{
struct wps_stop_reg_data *data = ctx;
if (hapd != data->current_hapd && hapd->wps != NULL)
- wps_registrar_complete(hapd->wps->registrar, data->uuid_e);
+ wps_registrar_complete(hapd->wps->registrar, data->uuid_e,
+ data->dev_pw, data->dev_pw_len);
return 0;
}
static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
- const u8 *uuid_e)
+ const u8 *uuid_e, const u8 *dev_pw,
+ size_t dev_pw_len)
{
struct hostapd_data *hapd = ctx;
char uuid[40];
@@ -209,6 +217,8 @@
mac_addr, uuid_e);
data.current_hapd = hapd;
data.uuid_e = uuid_e;
+ data.dev_pw = dev_pw;
+ data.dev_pw_len = dev_pw_len;
hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
}
@@ -984,6 +994,20 @@
}
+static void hostapd_wps_nfc_clear(struct wps_context *wps)
+{
+#ifdef CONFIG_WPS_NFC
+ wps->ap_nfc_dev_pw_id = 0;
+ wpabuf_free(wps->ap_nfc_dh_pubkey);
+ wps->ap_nfc_dh_pubkey = NULL;
+ wpabuf_free(wps->ap_nfc_dh_privkey);
+ wps->ap_nfc_dh_privkey = NULL;
+ wpabuf_free(wps->ap_nfc_dev_pw);
+ wps->ap_nfc_dev_pw = NULL;
+#endif /* CONFIG_WPS_NFC */
+}
+
+
void hostapd_deinit_wps(struct hostapd_data *hapd)
{
eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
@@ -1001,6 +1025,7 @@
wpabuf_free(hapd->wps->oob_conf.pubkey_hash);
wpabuf_free(hapd->wps->oob_conf.dev_password);
wps_free_pending_msgs(hapd->wps->upnp_msgs);
+ hostapd_wps_nfc_clear(hapd->wps);
os_free(hapd->wps);
hapd->wps = NULL;
hostapd_wps_clear_ies(hapd);
@@ -1098,6 +1123,24 @@
}
+static int wps_cancel(struct hostapd_data *hapd, void *ctx)
+{
+ if (hapd->wps == NULL)
+ return 0;
+
+ wps_registrar_wps_cancel(hapd->wps->registrar);
+ ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+
+ return 0;
+}
+
+
+int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+ return hostapd_wps_for_each(hapd, wps_cancel, NULL);
+}
+
+
#ifdef CONFIG_WPS_OOB
int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
char *path, char *method, char *name)
@@ -1154,7 +1197,8 @@
static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
const u8 *bssid,
- const u8 *ie, size_t ie_len)
+ const u8 *ie, size_t ie_len,
+ int ssi_signal)
{
struct hostapd_data *hapd = ctx;
struct wpabuf *wps_ie;
@@ -1471,3 +1515,156 @@
return wps_registrar_config_ap(hapd->wps->registrar, &cred);
}
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wps_nfc_password_token_data {
+ const u8 *oob_dev_pw;
+ size_t oob_dev_pw_len;
+ int added;
+};
+
+
+static int wps_add_nfc_password_token(struct hostapd_data *hapd, void *ctx)
+{
+ struct wps_nfc_password_token_data *data = ctx;
+ int ret;
+
+ if (hapd->wps == NULL)
+ return 0;
+ ret = wps_registrar_add_nfc_password_token(hapd->wps->registrar,
+ data->oob_dev_pw,
+ data->oob_dev_pw_len);
+ if (ret == 0)
+ data->added++;
+ return ret;
+}
+
+
+static int hostapd_wps_add_nfc_password_token(struct hostapd_data *hapd,
+ struct wps_parse_attr *attr)
+{
+ struct wps_nfc_password_token_data data;
+
+ data.oob_dev_pw = attr->oob_dev_password;
+ data.oob_dev_pw_len = attr->oob_dev_password_len;
+ data.added = 0;
+ if (hostapd_wps_for_each(hapd, wps_add_nfc_password_token, &data) < 0)
+ return -1;
+ return data.added ? 0 : -1;
+}
+
+
+static int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd,
+ const struct wpabuf *wps)
+{
+ struct wps_parse_attr attr;
+
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
+
+ if (wps_parse_msg(wps, &attr)) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
+ return -1;
+ }
+
+ if (attr.oob_dev_password)
+ return hostapd_wps_add_nfc_password_token(hapd, &attr);
+
+ wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
+ return -1;
+}
+
+
+int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
+ const struct wpabuf *data)
+{
+ const struct wpabuf *wps = data;
+ struct wpabuf *tmp = NULL;
+ int ret;
+
+ if (wpabuf_len(data) < 4)
+ return -1;
+
+ if (*wpabuf_head_u8(data) != 0x10) {
+ /* Assume this contains full NDEF record */
+ tmp = ndef_parse_wifi(data);
+ if (tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
+ return -1;
+ }
+ wps = tmp;
+ }
+
+ ret = hostapd_wps_nfc_tag_process(hapd, wps);
+ wpabuf_free(tmp);
+ return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
+ int ndef)
+{
+ struct wpabuf *ret;
+
+ if (hapd->wps == NULL)
+ return NULL;
+
+ ret = wps_get_oob_cred(hapd->wps);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
+{
+ return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id,
+ &hapd->conf->wps_nfc_dh_pubkey,
+ &hapd->conf->wps_nfc_dh_privkey,
+ &hapd->conf->wps_nfc_dev_pw);
+}
+
+
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
+{
+ struct wps_context *wps = hapd->wps;
+
+ if (wps == NULL)
+ return -1;
+
+ if (!hapd->conf->wps_nfc_dh_pubkey ||
+ !hapd->conf->wps_nfc_dh_privkey ||
+ !hapd->conf->wps_nfc_dev_pw ||
+ !hapd->conf->wps_nfc_dev_pw_id)
+ return -1;
+
+ hostapd_wps_nfc_clear(wps);
+ wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
+ wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
+ wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
+ wps->ap_nfc_dev_pw = wpabuf_dup(hapd->conf->wps_nfc_dev_pw);
+
+ if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
+ !wps->ap_nfc_dev_pw) {
+ hostapd_wps_nfc_clear(wps);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
+{
+ hostapd_wps_nfc_clear(hapd->wps);
+}
+
+#endif /* CONFIG_WPS_NFC */
diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h
index 9194225..f968e15 100644
--- a/src/ap/wps_hostapd.h
+++ b/src/ap/wps_hostapd.h
@@ -1,6 +1,6 @@
/*
* hostapd / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, 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 @@
const char *uuid, const char *pin, int timeout);
int hostapd_wps_button_pushed(struct hostapd_data *hapd,
const u8 *p2p_dev_addr);
+int hostapd_wps_cancel(struct hostapd_data *hapd);
int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
char *path, char *method, char *name);
int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
@@ -32,6 +33,13 @@
void hostapd_wps_update_ie(struct hostapd_data *hapd);
int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
const char *auth, const char *encr, const char *key);
+int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
+ const struct wpabuf *data);
+struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
+ int ndef);
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);
#else /* CONFIG_WPS */
@@ -67,6 +75,11 @@
return 0;
}
+static inline int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+ return 0;
+}
+
#endif /* CONFIG_WPS */
#endif /* WPS_HOSTAPD_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index b0d310d..d65675c 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -97,6 +97,11 @@
elems->p2p = pos;
elems->p2p_len = elen;
break;
+ case HS20_INDICATION_OUI_TYPE:
+ /* Hotspot 2.0 */
+ elems->hs20 = pos;
+ elems->hs20_len = elen;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@@ -257,6 +262,15 @@
elems->interworking = pos;
elems->interworking_len = elen;
break;
+ case WLAN_EID_EXT_CAPAB:
+ elems->ext_capab = pos;
+ elems->ext_capab_len = elen;
+ break;
+ case WLAN_EID_BSS_MAX_IDLE_PERIOD:
+ if (elen < 3)
+ break;
+ elems->bss_max_idle_period = pos;
+ break;
default:
unknown++;
if (!show_errors)
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index bfac88c..d9b2b6c 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -37,6 +37,9 @@
const u8 *p2p;
const u8 *link_id;
const u8 *interworking;
+ const u8 *hs20;
+ const u8 *ext_capab;
+ const u8 *bss_max_idle_period;
u8 ssid_len;
u8 supp_rates_len;
@@ -63,6 +66,8 @@
u8 vendor_ht_cap_len;
u8 p2p_len;
u8 interworking_len;
+ u8 hs20_len;
+ u8 ext_capab_len;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 3bef006..b4f9275 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -228,12 +228,25 @@
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
#define WLAN_EID_MMIE 76
+#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
+#define WLAN_EID_TFS_REQ 91
+#define WLAN_EID_TFS_RESP 92
+#define WLAN_EID_WNMSLEEP 93
#define WLAN_EID_TIME_ZONE 98
#define WLAN_EID_LINK_ID 101
#define WLAN_EID_INTERWORKING 107
#define WLAN_EID_ADV_PROTO 108
#define WLAN_EID_ROAMING_CONSORTIUM 111
#define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_VHT_CAP 191
+#define WLAN_EID_VHT_OPERATION 192
+#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
+#define WLAN_EID_VHT_WIDE_BW_CHSWITCH 194
+#define WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE 195
+#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196
+#define WLAN_EID_VHT_AID 197
+#define WLAN_EID_VHT_QUIET_CHANNEL 198
+#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199
#define WLAN_EID_VENDOR_SPECIFIC 221
@@ -254,6 +267,7 @@
#define WLAN_ACTION_VENDOR_SPECIFIC 127
/* Public action codes */
+#define WLAN_PA_20_40_BSS_COEX 0
#define WLAN_PA_VENDOR_SPECIFIC 9
#define WLAN_PA_GAS_INITIAL_REQ 10
#define WLAN_PA_GAS_INITIAL_RESP 11
@@ -487,6 +501,17 @@
} STRUCT_PACKED sa_query_resp;
struct {
u8 action;
+ u8 dialogtoken;
+ u8 variable[0];
+ } STRUCT_PACKED wnm_sleep_req;
+ struct {
+ u8 action;
+ u8 dialogtoken;
+ le16 keydata_len;
+ u8 variable[0];
+ } STRUCT_PACKED wnm_sleep_resp;
+ struct {
+ u8 action;
u8 variable[0];
} STRUCT_PACKED public_action;
struct {
@@ -534,6 +559,19 @@
u8 basic_set[16];
} STRUCT_PACKED;
+
+struct ieee80211_vht_capabilities {
+ le32 vht_capabilities_info;
+ u8 vht_supported_mcs_set[8];
+} STRUCT_PACKED;
+
+struct ieee80211_vht_operation {
+ u8 vht_op_info_chwidth;
+ u8 vht_op_info_chan_center_freq_seg0_idx;
+ u8 vht_op_info_chan_center_freq_seg1_idx;
+ le16 vht_basic_mcs_set;
+} STRUCT_PACKED;
+
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
@@ -630,12 +668,40 @@
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+/* VHT Defines */
+#define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0))
+#define VHT_CAP_MAX_MPDU_LENGTH_11454 ((u32) BIT(1))
+#define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ((u32) BIT(2))
+#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ ((u32) BIT(3))
+#define VHT_CAP_RXLDPC ((u32) BIT(4))
+#define VHT_CAP_SHORT_GI_80 ((u32) BIT(5))
+#define VHT_CAP_SHORT_GI_160 ((u32) BIT(6))
+#define VHT_CAP_TXSTBC ((u32) BIT(7))
+#define VHT_CAP_RXSTBC_1 ((u32) BIT(8))
+#define VHT_CAP_RXSTBC_2 ((u32) BIT(9))
+#define VHT_CAP_RXSTBC_3 ((u32) BIT(8) | BIT(9))
+#define VHT_CAP_RXSTBC_4 ((u32) BIT(10))
+#define VHT_CAP_SU_BEAMFORMER_CAPABLE ((u32) BIT(11))
+#define VHT_CAP_SU_BEAMFORMEE_CAPABLE ((u32) BIT(12))
+#define VHT_CAP_BEAMFORMER_ANTENNAS_MAX ((u32) BIT(13) | BIT(14))
+#define VHT_CAP_SOUNDING_DIMENTION_MAX ((u32) BIT(16) | BIT(17))
+#define VHT_CAP_MU_BEAMFORMER_CAPABLE ((u32) BIT(19))
+#define VHT_CAP_MU_BEAMFORMEE_CAPABLE ((u32) BIT(20))
+#define VHT_CAP_VHT_TXOP_PS ((u32) BIT(21))
+#define VHT_CAP_HTC_VHT ((u32) BIT(22))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT ((u32) BIT(23))
+#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB ((u32) BIT(27))
+#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB ((u32) BIT(26) | BIT(27))
+#define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28))
+#define VHT_CAP_TX_ANTENNA_PATTERN ((u32) BIT(29))
+
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
* 00:50:F2 */
#define WPA_IE_VENDOR_TYPE 0x0050f201
#define WPS_IE_VENDOR_TYPE 0x0050f204
#define OUI_WFA 0x506f9a
#define P2P_IE_VENDOR_TYPE 0x506f9a09
+#define HS20_IE_VENDOR_TYPE 0x506f9a10
#define WMM_OUI_TYPE 2
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
@@ -749,6 +815,16 @@
};
+#define HS20_INDICATION_OUI_TYPE 16
+#define HS20_ANQP_OUI_TYPE 17
+#define HS20_STYPE_QUERY_LIST 1
+#define HS20_STYPE_CAPABILITY_LIST 2
+#define HS20_STYPE_OPERATOR_FRIENDLY_NAME 3
+#define HS20_STYPE_WAN_METRICS 4
+#define HS20_STYPE_CONNECTION_CAPABILITY 5
+#define HS20_STYPE_NAI_HOME_REALM_QUERY 6
+#define HS20_STYPE_OPERATING_CLASS 7
+
/* Wi-Fi Direct (P2P) */
#define P2P_OUI_TYPE 9
@@ -915,4 +991,48 @@
#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+/* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */
+#define WLAN_20_40_BSS_COEX_INFO_REQ BIT(0)
+#define WLAN_20_40_BSS_COEX_40MHZ_INTOL BIT(1)
+#define WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ BIT(2)
+#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_REQ BIT(3)
+#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_GRNT BIT(4)
+
+struct ieee80211_2040_bss_coex_ie {
+ u8 element_id;
+ u8 length;
+ u8 coex_param;
+} STRUCT_PACKED;
+
+struct ieee80211_2040_intol_chan_report {
+ u8 element_id;
+ u8 length;
+ u8 op_class;
+ u8 variable[0]; /* Channel List */
+} STRUCT_PACKED;
+
+/* IEEE 802.11v - WNM-Sleep Mode element */
+struct wnm_sleep_element {
+ u8 eid; /* WLAN_EID_WNMSLEEP */
+ u8 len;
+ u8 action_type; /* WLAN_WNM_SLEEP_ENTER/EXIT */
+ u8 status;
+ le16 intval;
+} STRUCT_PACKED;
+
+enum wnm_sleep_mode_response_status {
+ WNM_STATUS_SLEEP_ACCEPT = 0,
+ WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE = 1,
+ WNM_STATUS_DENIED_ACTION = 2,
+ WNM_STATUS_DENIED_TMP = 3,
+ WNM_STATUS_DENIED_KEY = 4,
+ WNM_STATUS_DENIED_OTHER_WNM_SERVICE = 5
+};
+
+/* WNM-Sleep Mode subelement IDs */
+enum wnm_sleep_mode_subelement_id {
+ WNM_SLEEP_SUBELEM_GTK = 0,
+ WNM_SLEEP_SUBELEM_IGTK = 1
+};
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 5768fdd..a440b69 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -120,6 +120,8 @@
#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ "
/* parameters: <peer address> */
#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP "
+/* parameters: <peer address> <status> */
+#define P2P_EVENT_PROV_DISC_FAILURE "P2P-PROV-DISC-FAILURE"
/* parameters: <freq> <src addr> <dialog token> <update indicator> <TLVs> */
#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ "
/* parameters: <src addr> <update indicator> <TLVs> */
@@ -143,6 +145,27 @@
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
+/* BSS command information masks */
+
+#define WPA_BSS_MASK_ALL 0xFFFFFFFF
+#define WPA_BSS_MASK_ID BIT(0)
+#define WPA_BSS_MASK_BSSID BIT(1)
+#define WPA_BSS_MASK_FREQ BIT(2)
+#define WPA_BSS_MASK_BEACON_INT BIT(3)
+#define WPA_BSS_MASK_CAPABILITIES BIT(4)
+#define WPA_BSS_MASK_QUAL BIT(5)
+#define WPA_BSS_MASK_NOISE BIT(6)
+#define WPA_BSS_MASK_LEVEL BIT(7)
+#define WPA_BSS_MASK_TSF BIT(8)
+#define WPA_BSS_MASK_AGE BIT(9)
+#define WPA_BSS_MASK_IE BIT(10)
+#define WPA_BSS_MASK_FLAGS BIT(11)
+#define WPA_BSS_MASK_SSID BIT(12)
+#define WPA_BSS_MASK_WPS_SCAN BIT(13)
+#define WPA_BSS_MASK_P2P_SCAN BIT(14)
+#define WPA_BSS_MASK_INTERNETW BIT(15)
+
+
/* wpa_supplicant/hostapd control interface access */
/**
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 1171f29..8506fff 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / wrapper functions for libcrypto
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,6 +14,7 @@
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/dh.h>
+#include <openssl/hmac.h>
#include "common.h"
#include "wpabuf.h"
@@ -452,6 +453,41 @@
}
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+ DH *dh;
+
+ dh = DH_new();
+ if (dh == NULL)
+ return NULL;
+
+ dh->g = BN_new();
+ if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
+ goto err;
+
+ dh->p = get_group5_prime();
+ if (dh->p == NULL)
+ goto err;
+
+ dh->priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+ if (dh->priv_key == NULL)
+ goto err;
+
+ dh->pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+ if (dh->pub_key == NULL)
+ goto err;
+
+ if (DH_generate_key(dh) != 1)
+ goto err;
+
+ return dh;
+
+err:
+ DH_free(dh);
+ return NULL;
+}
+
+
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private)
{
@@ -497,3 +533,93 @@
dh = ctx;
DH_free(dh);
}
+
+
+struct crypto_hash {
+ HMAC_CTX ctx;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_hash *ctx;
+ const EVP_MD *md;
+
+ switch (alg) {
+#ifndef OPENSSL_NO_MD5
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ md = EVP_md5();
+ break;
+#endif /* OPENSSL_NO_MD5 */
+#ifndef OPENSSL_NO_SHA
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ md = EVP_sha1();
+ break;
+#endif /* OPENSSL_NO_SHA */
+#ifndef OPENSSL_NO_SHA256
+#ifdef CONFIG_SHA256
+ case CRYPTO_HASH_ALG_HMAC_SHA256:
+ md = EVP_sha256();
+ break;
+#endif /* CONFIG_SHA256 */
+#endif /* OPENSSL_NO_SHA256 */
+ default:
+ return NULL;
+ }
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+ HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
+#else /* openssl < 0.9.9 */
+ if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
+ os_free(ctx);
+ return NULL;
+ }
+#endif /* openssl < 0.9.9 */
+
+ return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+ if (ctx == NULL)
+ return;
+ HMAC_Update(&ctx->ctx, data, len);
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+ unsigned int mdlen;
+ int res;
+
+ if (ctx == NULL)
+ return -2;
+
+ if (mac == NULL || len == NULL) {
+ os_free(ctx);
+ return 0;
+ }
+
+ mdlen = *len;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+ HMAC_Final(&ctx->ctx, mac, &mdlen);
+ res = 1;
+#else /* openssl < 0.9.9 */
+ res = HMAC_Final(&ctx->ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+ HMAC_CTX_cleanup(&ctx->ctx);
+ os_free(ctx);
+
+ if (res == 1) {
+ *len = mdlen;
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/src/crypto/dh_group5.c b/src/crypto/dh_group5.c
index 9a94ca5..ccdbfc8 100644
--- a/src/crypto/dh_group5.c
+++ b/src/crypto/dh_group5.c
@@ -1,6 +1,6 @@
/*
* Diffie-Hellman group 5 operations
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,6 +22,12 @@
}
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+ return (void *) 1;
+}
+
+
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private)
{
diff --git a/src/crypto/dh_group5.h b/src/crypto/dh_group5.h
index 8813427..abee8ea 100644
--- a/src/crypto/dh_group5.h
+++ b/src/crypto/dh_group5.h
@@ -1,6 +1,6 @@
/*
* Diffie-Hellman group 5 operations
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009, 2012, 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 @@
#define DH_GROUP5_H
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ);
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ);
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private);
void dh5_free(void *ctx);
diff --git a/src/crypto/random.c b/src/crypto/random.c
index 55e9391..d85c3e6 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -128,8 +128,6 @@
static unsigned int count = 0;
count++;
- wpa_printf(MSG_MSGDUMP, "Add randomness: count=%u entropy=%u",
- count, entropy);
if (entropy > MIN_COLLECT_ENTROPY && (count & 0x3ff) != 0) {
/*
* No need to add more entropy at this point, so save CPU and
@@ -137,6 +135,8 @@
*/
return;
}
+ wpa_printf(MSG_EXCESSIVE, "Add randomness: count=%u entropy=%u",
+ count, entropy);
os_get_time(&t);
wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 2bd3bbb..990f6e6 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -21,8 +21,10 @@
};
enum tls_event {
+ TLS_CERT_CHAIN_SUCCESS,
TLS_CERT_CHAIN_FAILURE,
- TLS_PEER_CERTIFICATE
+ TLS_PEER_CERTIFICATE,
+ TLS_ALERT
};
/*
@@ -57,6 +59,12 @@
const u8 *hash;
size_t hash_len;
} peer_cert;
+
+ struct {
+ int is_local;
+ const char *type;
+ const char *description;
+ } alert;
};
struct tls_config {
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index aaa920b..09b02e4 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -527,6 +527,15 @@
else
conn->write_alerts++;
}
+ if (tls_global->event_cb != NULL) {
+ union tls_event_data ev;
+ os_memset(&ev, 0, sizeof(ev));
+ ev.alert.is_local = !(where & SSL_CB_READ);
+ ev.alert.type = SSL_alert_type_string_long(ret);
+ ev.alert.description = SSL_alert_desc_string_long(ret);
+ tls_global->event_cb(tls_global->cb_ctx, TLS_ALERT,
+ &ev);
+ }
} else if (where & SSL_CB_EXIT && ret <= 0) {
wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
str, ret == 0 ? "failed" : "error",
@@ -1274,6 +1283,10 @@
TLS_FAIL_SERVER_CHAIN_PROBE);
}
+ if (preverify_ok && tls_global->event_cb != NULL)
+ tls_global->event_cb(tls_global->cb_ctx,
+ TLS_CERT_CHAIN_SUCCESS, NULL);
+
return preverify_ok;
}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index f1d4a14..0aab61e 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -100,6 +100,16 @@
*/
u8 a_mpdu_params;
+ /**
+ * vht_capab - VHT (IEEE 802.11ac) capabilities
+ */
+ u32 vht_capab;
+
+ /**
+ * vht_mcs_set - VHT MCS (IEEE 802.11ac) rate parameters
+ */
+ u8 vht_mcs_set[8];
+
unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
};
@@ -333,6 +343,13 @@
int freq;
/**
+ * bg_scan_period - Background scan period in seconds, 0 to disable
+ * background scan, or -1 to indicate no change to default driver
+ * configuration
+ */
+ int bg_scan_period;
+
+ /**
* wpa_ie - WPA information element for (Re)Association Request
* WPA information element to be included in (Re)Association
* Request (including information element id and length). Use
@@ -707,6 +724,13 @@
* enabled.
*/
u8 access_network_type;
+
+ /**
+ * ap_max_inactivity - Timeout in seconds to detect STA's inactivity
+ *
+ * This is used by driver which advertises this capability.
+ */
+ int ap_max_inactivity;
};
/**
@@ -726,6 +750,7 @@
#define WPA_DRIVER_CAPA_ENC_WEP104 0x00000002
#define WPA_DRIVER_CAPA_ENC_TKIP 0x00000004
#define WPA_DRIVER_CAPA_ENC_CCMP 0x00000008
+#define WPA_DRIVER_CAPA_ENC_WEP128 0x00000010
unsigned int enc;
#define WPA_DRIVER_AUTH_OPEN 0x00000001
@@ -790,6 +815,8 @@
#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD 0x00200000
/* Driver supports U-APSD in AP mode */
#define WPA_DRIVER_FLAGS_AP_UAPSD 0x00400000
+/* Driver supports inactivity timer in AP mode */
+#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER 0x00800000
unsigned int flags;
int max_scan_ssids;
@@ -2003,6 +2030,16 @@
int (*deinit_ap)(void *priv);
/**
+ * deinit_p2p_cli - Deinitialize P2P client mode
+ * @priv: Private driver interface data
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ *
+ * This optional function can be used to disable P2P client mode. It
+ * can be used to change the interface type back to station mode.
+ */
+ int (*deinit_p2p_cli)(void *priv);
+
+ /**
* suspend - Notification on system suspend/hibernate event
* @priv: Private driver interface data
*/
@@ -2508,19 +2545,30 @@
*/
void (*poll_client)(void *priv, const u8 *own_addr,
const u8 *addr, int qos);
-#ifdef ANDROID_P2P
+
/**
- * switch_channel - Announce channel switch and migrate the GO to a
- * given frequency.
+ * radio_disable - Disable/enable radio
* @priv: Private driver interface data
- * @freq: frequency in MHz
+ * @disabled: 1=disable 0=enable radio
* Returns: 0 on success, -1 on failure
*
- * This function is used to move the GO to the legacy STA channel to avoid
- * frequency conflict in single channel concurrency.
+ * This optional command is for testing purposes. It can be used to
+ * disable the radio on a testbed device to simulate out-of-radio-range
+ * conditions.
+ */
+ int (*radio_disable)(void *priv, int disabled);
+
+ /**
+ * switch_channel - Announce channel switch and migrate the GO to the
+ * given frequency
+ * @priv: Private driver interface data
+ * @freq: Frequency in MHz
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to move the GO to the legacy STA channel to
+ * avoid frequency conflict in single channel concurrency.
*/
int (*switch_channel)(void *priv, unsigned int freq);
-#endif
};
@@ -2951,7 +2999,14 @@
/**
* EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
*/
- EVENT_EAPOL_TX_STATUS
+ EVENT_EAPOL_TX_STATUS,
+
+ /**
+ * EVENT_CH_SWITCH - AP or GO decided to switch channels
+ *
+ * Described in wpa_event_data.ch_switch
+ * */
+ EVENT_CH_SWITCH
};
@@ -3267,7 +3322,7 @@
const u8 *frame;
size_t frame_len;
u32 datarate;
- u32 ssi_signal;
+ int ssi_signal; /* dBm */
} rx_mgmt;
/**
@@ -3385,6 +3440,11 @@
* ie_len - Length of ie buffer in octets
*/
size_t ie_len;
+
+ /**
+ * signal - signal strength in dBm (or 0 if not available)
+ */
+ int ssi_signal;
} rx_probe_req;
/**
@@ -3541,6 +3601,18 @@
int data_len;
int ack;
} eapol_tx_status;
+
+ /**
+ * struct ch_switch
+ * @freq: Frequency of new channel in MHz
+ * @ht_enabled: Whether this is an HT channel
+ * @ch_offset: Secondary channel offset
+ */
+ struct ch_switch {
+ int freq;
+ int ht_enabled;
+ int ch_offset;
+ } ch_switch;
};
/**
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index b17d1a6..73898d3 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -5,14 +5,8 @@
* Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
* Copyright (c) 2009, Atheros Communications
*
- * 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 "includes.h"
@@ -39,11 +33,11 @@
#ifdef CONFIG_WPS
#include <netpacket/packet.h>
+#endif /* CONFIG_WPS */
#ifndef ETH_P_80211_RAW
#define ETH_P_80211_RAW 0x0019
#endif
-#endif /* CONFIG_WPS */
#include "linux_wext.h"
@@ -73,6 +67,7 @@
struct wpabuf *wpa_ie;
struct wpabuf *wps_beacon_ie;
struct wpabuf *wps_probe_resp_ie;
+ u8 own_addr[ETH_ALEN];
};
static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
@@ -732,8 +727,8 @@
}
#ifdef CONFIG_WPS
-static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
+static void atheros_raw_recv_wps(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
{
struct atheros_driver_data *drv = ctx;
const struct ieee80211_mgmt *mgmt;
@@ -762,28 +757,139 @@
}
#endif /* CONFIG_WPS */
-static int atheros_receive_probe_req(struct atheros_driver_data *drv)
+#ifdef CONFIG_IEEE80211R
+static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct atheros_driver_data *drv = ctx;
+ union wpa_event_data event;
+ const struct ieee80211_mgmt *mgmt;
+ u16 fc;
+ u16 stype;
+ int ielen;
+ const u8 *iebuf;
+
+ /* Do 11R processing for ASSOC/AUTH/FT ACTION frames */
+ if (len < IEEE80211_HDRLEN)
+ return;
+ mgmt = (const struct ieee80211_mgmt *) buf;
+
+ fc = le_to_host16(mgmt->frame_control);
+
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+ return;
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
+ (int) len);
+
+ if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
+ __func__);
+ return;
+ }
+ switch (stype) {
+ case WLAN_FC_STYPE_ASSOC_REQ:
+ if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.assoc_req))
+ break;
+ ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
+ iebuf = mgmt->u.assoc_req.variable;
+ drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0);
+ break;
+ case WLAN_FC_STYPE_REASSOC_REQ:
+ if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.reassoc_req))
+ break;
+ ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
+ iebuf = mgmt->u.reassoc_req.variable;
+ 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);
+ break;
+ case WLAN_FC_STYPE_AUTH:
+ if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.auth))
+ break;
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
+ os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN);
+ event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+ event.auth.status_code =
+ le_to_host16(mgmt->u.auth.status_code);
+ event.auth.auth_transaction =
+ le_to_host16(mgmt->u.auth.auth_transaction);
+ event.auth.ies = mgmt->u.auth.variable;
+ event.auth.ies_len = len - IEEE80211_HDRLEN -
+ sizeof(mgmt->u.auth);
+ wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event);
+ break;
+ default:
+ break;
+ }
+}
+#endif /* CONFIG_IEEE80211R */
+
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
+static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+#ifdef CONFIG_WPS
+ atheros_raw_recv_wps(ctx, src_addr, buf, len);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_IEEE80211R
+ atheros_raw_recv_11r(ctx, src_addr, buf, len);
+#endif /* CONFIG_IEEE80211R */
+}
+#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
+
+static int atheros_receive_pkt(struct atheros_driver_data *drv)
{
int ret = 0;
-#ifdef CONFIG_WPS
struct ieee80211req_set_filter filt;
wpa_printf(MSG_DEBUG, "%s Enter", __func__);
- filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ;
+ filt.app_filterype = 0;
+#ifdef CONFIG_WPS
+ filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_IEEE80211R
+ filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
+ IEEE80211_FILTER_TYPE_AUTH);
+#endif
+ if (filt.app_filterype) {
+ ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
+ sizeof(struct ieee80211req_set_filter));
+ if (ret)
+ return ret;
+ }
- ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
- sizeof(struct ieee80211req_set_filter));
- if (ret)
- return ret;
-
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
atheros_raw_receive, drv, 1);
if (drv->sock_raw == NULL)
return -1;
-#endif /* CONFIG_WPS */
+#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
+ if (l2_packet_get_own_addr(drv->sock_xmit, drv->own_addr))
+ return -1;
return ret;
}
+static int atheros_reset_appfilter(struct atheros_driver_data *drv)
+{
+ struct ieee80211req_set_filter filt;
+ filt.app_filterype = 0;
+ return set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
+ sizeof(struct ieee80211req_set_filter));
+}
+
#ifdef CONFIG_WPS
static int
atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
@@ -852,6 +958,84 @@
#define atheros_set_ap_wps_ie NULL
#endif /* CONFIG_WPS */
+#ifdef CONFIG_IEEE80211R
+static int
+atheros_sta_auth(void *priv, const u8 *own_addr, const u8 *addr, u16 seq,
+ u16 status_code, const u8 *ie, size_t len)
+{
+ struct atheros_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d",
+ __func__, ether_sprintf(addr), status_code);
+
+ mlme.im_op = IEEE80211_MLME_AUTH;
+ mlme.im_reason = status_code;
+ mlme.im_seq = seq;
+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ mlme.im_optie_len = len;
+ if (len) {
+ if (len < IEEE80211_MAX_OPT_IE) {
+ os_memcpy(mlme.im_optie, ie, len);
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Not enough space to copy "
+ "opt_ie STA (addr " MACSTR " reason %d, "
+ "ie_len %d)",
+ __func__, MAC2STR(addr), status_code,
+ (int) len);
+ return -1;
+ }
+ }
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to auth STA (addr " MACSTR
+ " reason %d)",
+ __func__, MAC2STR(addr), status_code);
+ }
+ return ret;
+}
+
+static int
+atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr,
+ int reassoc, u16 status_code, const u8 *ie, size_t len)
+{
+ struct atheros_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d reassoc %d",
+ __func__, ether_sprintf(addr), status_code, reassoc);
+
+ if (reassoc)
+ mlme.im_op = IEEE80211_MLME_REASSOC;
+ else
+ mlme.im_op = IEEE80211_MLME_ASSOC;
+ mlme.im_reason = status_code;
+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ mlme.im_optie_len = len;
+ if (len) {
+ if (len < IEEE80211_MAX_OPT_IE) {
+ os_memcpy(mlme.im_optie, ie, len);
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Not enough space to copy "
+ "opt_ie STA (addr " MACSTR " reason %d, "
+ "ie_len %d)",
+ __func__, MAC2STR(addr), status_code,
+ (int) len);
+ return -1;
+ }
+ }
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to assoc STA (addr " MACSTR
+ " reason %d)",
+ __func__, MAC2STR(addr), status_code);
+ }
+ return ret;
+}
+#endif /* CONFIG_IEEE80211R */
+
static void
atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
{
@@ -980,6 +1164,9 @@
* so all are enabled for WPS... ugh.
*/
wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
+#endif /* CONFIG_WPS */
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
+#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */
} else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
/*
* Atheros driver uses a hack to pass Probe Request frames as a
@@ -987,7 +1174,6 @@
* packet sniffing) didn't work when bridging.
* Format: "Manage.prob_req <frame len>" | zero padding | frame
*/
-#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */
int len = atoi(custom + 16);
if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
@@ -996,7 +1182,40 @@
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + WPS_FRAM_TAG_SIZE, len);
-#endif /* CONFIG_WPS */
+ } else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) {
+ /* Format: "Manage.assoc_req <frame len>" | zero padding |
+ * frame */
+ int len = atoi(custom + 17);
+ if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
+ "assoc_req/auth event length %d", len);
+ return;
+ }
+ atheros_raw_receive(drv, NULL,
+ (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+ } else if (strncmp(custom, "Manage.action ", 14) == 0) {
+ /* Format: "Manage.assoc_req <frame len>" | zero padding |
+ * frame */
+ int len = atoi(custom + 14);
+ if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
+ "assoc_req/auth event length %d", len);
+ return;
+ }
+ atheros_raw_receive(drv, NULL,
+ (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+ } else if (strncmp(custom, "Manage.auth ", 12) == 0) {
+ /* Format: "Manage.auth <frame len>" | zero padding | frame
+ */
+ int len = atoi(custom + 12);
+ if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
+ "assoc_req/auth event length %d", len);
+ return;
+ }
+ atheros_raw_receive(drv, NULL,
+ (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+#endif /* CONFIG_WPS or CONFIG_IEEE80211R */
}
}
@@ -1278,7 +1497,7 @@
linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
atheros_set_privacy(drv, 0); /* default to no privacy */
- atheros_receive_probe_req(drv);
+ atheros_receive_pkt(drv);
if (atheros_wireless_event_init(drv))
goto bad;
@@ -1302,6 +1521,7 @@
{
struct atheros_driver_data *drv = priv;
+ atheros_reset_appfilter(drv);
netlink_deinit(drv->netlink);
(void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
if (drv->ioctl_sock >= 0)
@@ -1348,7 +1568,6 @@
memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
iwr.u.essid.pointer = (caddr_t) buf;
- iwr.u.essid.length = len;
iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ?
IW_ESSID_MAX_SIZE : len;
@@ -1421,6 +1640,75 @@
return 0;
}
+
+#ifdef CONFIG_IEEE80211R
+
+static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
+ int noack)
+{
+ struct atheros_driver_data *drv = priv;
+ u8 buf[1510];
+ const struct ieee80211_mgmt *mgmt;
+ struct ieee80211req_mgmtbuf *mgmt_frm;
+
+ mgmt = (const struct ieee80211_mgmt *) frm;
+ wpa_printf(MSG_DEBUG, "%s frmlen = %lu " MACSTR, __func__,
+ (unsigned long) data_len, MAC2STR(mgmt->da));
+ mgmt_frm = (struct ieee80211req_mgmtbuf *) buf;
+ memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN);
+ mgmt_frm->buflen = data_len;
+ if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) {
+ wpa_printf(MSG_INFO, "atheros: Too long frame for "
+ "atheros_send_mgmt (%u)", (unsigned int) data_len);
+ return -1;
+ }
+ os_memcpy(&mgmt_frm->buf[0], frm, data_len);
+ return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
+ sizeof(struct ieee80211req_mgmtbuf) + data_len);
+}
+
+
+static int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie,
+ size_t tspec_ielen)
+{
+ struct atheros_driver_data *drv = priv;
+ int retv;
+ struct ieee80211req_res req;
+ struct ieee80211req_res_addts *addts = &req.u.addts;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ req.type = IEEE80211_RESREQ_ADDTS;
+ os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN);
+ os_memcpy(addts->tspecie, tspec_ie, tspec_ielen);
+ retv = set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req,
+ sizeof(struct ieee80211req_res));
+ if (retv < 0) {
+ wpa_printf(MSG_DEBUG, "%s IEEE80211_IOCTL_RES_REQ FAILED "
+ "retv = %d", __func__, retv);
+ return -1;
+ }
+ os_memcpy(tspec_ie, addts->tspecie, tspec_ielen);
+ return addts->status;
+}
+
+
+static int atheros_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
+{
+ struct atheros_driver_data *drv = priv;
+ struct ieee80211req_res req;
+ struct ieee80211req_res_addnode *addnode = &req.u.addnode;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ req.type = IEEE80211_RESREQ_ADDNODE;
+ os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN);
+ addnode->auth_alg = auth_alg;
+ return set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req,
+ sizeof(struct ieee80211req_res));
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
const struct wpa_driver_ops wpa_driver_atheros_ops = {
.name = "atheros",
.hapd_init = atheros_init,
@@ -1444,4 +1732,11 @@
.set_ap_wps_ie = atheros_set_ap_wps_ie,
.set_authmode = atheros_set_authmode,
.set_ap = atheros_set_ap,
+#ifdef CONFIG_IEEE80211R
+ .sta_assoc = atheros_sta_assoc,
+ .sta_auth = atheros_sta_auth,
+ .send_mlme = atheros_send_mgmt,
+ .add_tspec = atheros_add_tspec,
+ .add_sta_node = atheros_add_sta_node,
+#endif /* CONFIG_IEEE80211R */
};
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 4596a51..67abb67 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -3,14 +3,8 @@
* Copyright (c) 2004, Sam Leffler <sam@errno.com>
* Copyright (c) 2004, 2Wire, 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.
*/
#include "includes.h"
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 345e851..81856aa 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -77,6 +77,7 @@
E2S(SCHED_SCAN_STOPPED);
E2S(DRIVER_CLIENT_POLL_OK);
E2S(EAPOL_TX_STATUS);
+ E2S(CH_SWITCH);
}
return "UNKNOWN";
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
index edb086f..bb48011 100644
--- a/src/drivers/driver_madwifi.c
+++ b/src/drivers/driver_madwifi.c
@@ -4,14 +4,8 @@
* Copyright (c) 2004, Video54 Technologies
* Copyright (c) 2004-2007, 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.
*
* While this driver wrapper supports both AP (hostapd) and station
* (wpa_supplicant) operations, the station side is deprecated and
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 8795104..d54d0f5 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -189,6 +189,7 @@
unsigned int beacon_set:1;
unsigned int added_if_into_bridge:1;
unsigned int added_bridge:1;
+ unsigned int in_deinit:1;
u8 addr[ETH_ALEN];
@@ -456,6 +457,7 @@
valid_data);
}
+
int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
@@ -797,10 +799,28 @@
del ? "removed" : "added");
if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
- if (del)
+ if (del) {
+ if (drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "nl80211: if_removed "
+ "already set - ignore event");
+ return;
+ }
drv->if_removed = 1;
- else
+ } 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;
+ }
}
wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
@@ -917,6 +937,14 @@
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
"event since interface %s is down",
namebuf);
+ } else if (if_nametoindex(drv->first_bss.ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+ "event since interface %s does not exist",
+ drv->first_bss.ifname);
+ } else if (drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+ "event since interface %s is marked "
+ "removed", drv->first_bss.ifname);
} else {
wpa_printf(MSG_DEBUG, "nl80211: Interface up");
drv->if_disabled = 0;
@@ -1103,6 +1131,7 @@
}
event.assoc_info.freq = drv->assoc_freq;
+
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
}
@@ -1176,9 +1205,43 @@
drv->associated = 0;
os_memset(&data, 0, sizeof(data));
if (reason)
- data.disassoc_info.reason_code = nla_get_u16(reason);
- data.disassoc_info.locally_generated = by_ap == NULL;
- wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
+ data.deauth_info.reason_code = nla_get_u16(reason);
+ data.deauth_info.locally_generated = by_ap == NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
+}
+
+
+static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *freq, struct nlattr *type)
+{
+ union wpa_event_data data;
+ int ht_enabled = 1;
+ int chan_offset = 0;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
+
+ if (!freq || !type)
+ return;
+
+ switch (nla_get_u32(type)) {
+ case NL80211_CHAN_NO_HT:
+ ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ chan_offset = -1;
+ break;
+ }
+
+ data.ch_switch.freq = nla_get_u32(freq);
+ data.ch_switch.ht_enabled = ht_enabled;
+ data.ch_switch.ch_offset = chan_offset;
+
+ wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
}
@@ -1208,11 +1271,13 @@
static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
- struct nlattr *freq, const u8 *frame, size_t len)
+ struct nlattr *freq, struct nlattr *sig,
+ const u8 *frame, size_t len)
{
const struct ieee80211_mgmt *mgmt;
union wpa_event_data event;
u16 fc, stype;
+ int ssi_signal = 0;
mgmt = (const struct ieee80211_mgmt *) frame;
if (len < 24) {
@@ -1223,6 +1288,9 @@
fc = le_to_host16(mgmt->frame_control);
stype = WLAN_FC_GET_STYPE(fc);
+ if (sig)
+ ssi_signal = (s32) nla_get_u32(sig);
+
os_memset(&event, 0, sizeof(event));
if (freq) {
event.rx_action.freq = nla_get_u32(freq);
@@ -1239,6 +1307,7 @@
} 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);
}
}
@@ -1379,7 +1448,7 @@
enum nl80211_commands cmd, struct nlattr *frame,
struct nlattr *addr, struct nlattr *timed_out,
struct nlattr *freq, struct nlattr *ack,
- struct nlattr *cookie)
+ struct nlattr *cookie, struct nlattr *sig)
{
if (timed_out && addr) {
mlme_timeout_event(drv, cmd, addr);
@@ -1412,7 +1481,8 @@
nla_data(frame), nla_len(frame));
break;
case NL80211_CMD_FRAME:
- mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame));
+ mlme_event_mgmt(drv, freq, sig, nla_data(frame),
+ nla_len(frame));
break;
case NL80211_CMD_FRAME_TX_STATUS:
mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
@@ -2084,7 +2154,8 @@
mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
- tb[NL80211_ATTR_COOKIE]);
+ tb[NL80211_ATTR_COOKIE],
+ tb[NL80211_ATTR_RX_SIGNAL_DBM]);
break;
case NL80211_CMD_CONNECT:
case NL80211_CMD_ROAM:
@@ -2094,6 +2165,10 @@
tb[NL80211_ATTR_REQ_IE],
tb[NL80211_ATTR_RESP_IE]);
break;
+ case NL80211_CMD_CH_SWITCH_NOTIFY:
+ mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
+ tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+ break;
case NL80211_CMD_DISCONNECT:
mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
tb[NL80211_ATTR_MAC],
@@ -2176,7 +2251,7 @@
struct nl80211_global *global = arg;
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct wpa_driver_nl80211_data *drv;
+ struct wpa_driver_nl80211_data *drv, *tmp;
int ifidx = -1;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -2185,15 +2260,11 @@
if (tb[NL80211_ATTR_IFINDEX])
ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
- dl_list_for_each(drv, &global->interfaces,
- struct wpa_driver_nl80211_data, list) {
+ dl_list_for_each_safe(drv, tmp, &global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
if (ifidx == -1 || ifidx == drv->ifindex ||
- have_ifidx(drv, ifidx)) {
+ have_ifidx(drv, ifidx))
do_process_drv_event(drv, gnlh->cmd, tb);
-#ifdef ANDROID_P2P
- break;
-#endif
- }
}
return NL_SKIP;
@@ -2215,7 +2286,8 @@
mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
- tb[NL80211_ATTR_COOKIE]);
+ tb[NL80211_ATTR_COOKIE],
+ tb[NL80211_ATTR_RX_SIGNAL_DBM]);
break;
case NL80211_CMD_UNEXPECTED_FRAME:
nl80211_spurious_frame(bss, tb, 0);
@@ -2504,6 +2576,9 @@
if (flags & NL80211_FEATURE_SK_TX_STATUS)
info->data_tx_status = 1;
+
+ if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
+ capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
}
if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
@@ -2571,17 +2646,29 @@
drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
- drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+#ifndef ANDROID_P2P
+ if (!info.device_ap_sme)
+#endif
+ drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
drv->device_ap_sme = info.device_ap_sme;
drv->poll_command_supported = info.poll_command_supported;
drv->data_tx_status = info.data_tx_status;
+#ifdef ANDROID_P2P
+ if(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
+ /* Driver is new enough to support monitorless mode*/
+ wpa_printf(MSG_DEBUG, "nl80211: Driver is new "
+ "enough to support monitor-less mode");
+ drv->use_monitor = 0;
+ }
+#else
/*
* If poll command is supported mac80211 is new enough to
* have everything we need to not need monitor interfaces.
*/
drv->use_monitor = !info.poll_command_supported;
+#endif
if (drv->device_ap_sme && drv->use_monitor) {
/*
@@ -2803,10 +2890,7 @@
u8 data[2048];
struct msghdr msg;
struct iovec entry;
- struct {
- struct cmsghdr cm;
- char control[512];
- } control;
+ u8 control[512];
struct cmsghdr *cmsg;
int res, found_ee = 0, found_wifi = 0, acked = 0;
union wpa_event_data event;
@@ -3309,6 +3393,7 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
+ bss->in_deinit = 1;
if (drv->data_tx_status)
eloop_unregister_read_sock(drv->eapol_tx_sock);
if (drv->eapol_tx_sock >= 0)
@@ -3467,6 +3552,8 @@
}
if (params->p2p_probe) {
+ wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+
/*
* Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
* by masking out everything else apart from the OFDM rates 6,
@@ -4731,6 +4818,18 @@
os_memcpy(mode->mcs_set, mcs, 16);
}
+ if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
+ mode->vht_capab = nla_get_u32(
+ tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
+ }
+
+ if (tb_band[NL80211_BAND_ATTR_VHT_MCS_SET] &&
+ nla_len(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])) {
+ u8 *mcs;
+ mcs = nla_data(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+ os_memcpy(mode->vht_mcs_set, mcs, 8);
+ }
+
nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
nla_len(nl_freq), freq_policy);
@@ -5191,7 +5290,9 @@
if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
if (freq == 0)
freq = bss->freq;
- return nl80211_send_frame_cmd(bss, freq, 0,
+ return nl80211_send_frame_cmd(bss, freq,
+ (int) freq == bss->freq ? 0 :
+ wait_time,
data, data_len,
&drv->send_action_cookie,
no_cck, noack, offchanok);
@@ -5403,6 +5504,11 @@
wpabuf_head(params->assocresp_ies));
}
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
+ NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
+ params->ap_max_inactivity);
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -5413,7 +5519,6 @@
params->short_slot_time, params->ht_opmode,
params->isolate, params->basic_rates);
}
-
return ret;
nla_put_failure:
nlmsg_free(msg);
@@ -5851,8 +5956,8 @@
case IEEE80211_RADIOTAP_RATE:
datarate = *iter.this_arg * 5;
break;
- case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
- ssi_signal = *iter.this_arg;
+ case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+ ssi_signal = (s8) *iter.this_arg;
break;
}
}
@@ -6149,7 +6254,6 @@
if (nl80211_mgmt_subscribe_ap(bss))
return -1;
-#ifndef ANDROID_P2P
if (drv->device_ap_sme && !drv->use_monitor)
if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
return -1;
@@ -6157,15 +6261,17 @@
if (!drv->device_ap_sme && drv->use_monitor &&
nl80211_create_monitor_interface(drv) &&
!drv->device_ap_sme)
-#else
- if (drv->device_ap_sme)
+ return -1;
+
+#ifdef ANDROID_P2P
+ if (drv->device_ap_sme && drv->use_monitor)
if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
return -1;
if (drv->use_monitor &&
nl80211_create_monitor_interface(drv))
-#endif
return -1;
+#endif
if (drv->device_ap_sme &&
wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
@@ -6568,6 +6674,12 @@
wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
}
+ 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);
@@ -6765,6 +6877,12 @@
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);
@@ -6980,7 +7098,7 @@
nl80211_mgmt_unsubscribe(bss, "mode change");
}
- if (!is_ap_interface(nlmode) &&
+ if (!bss->in_deinit && !is_ap_interface(nlmode) &&
nl80211_mgmt_subscribe_non_ap(bss) < 0)
wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
"frame processing - ignore for now");
@@ -7402,8 +7520,12 @@
int reason)
{
struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt mgmt;
+ if (drv->device_ap_sme)
+ return wpa_driver_nl80211_sta_remove(bss, addr);
+
memset(&mgmt, 0, sizeof(mgmt));
mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_DEAUTH);
@@ -7421,8 +7543,12 @@
int reason)
{
struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt mgmt;
+ if (drv->device_ap_sme)
+ return wpa_driver_nl80211_sta_remove(bss, addr);
+
memset(&mgmt, 0, sizeof(mgmt));
mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_DISASSOC);
@@ -7967,6 +8093,9 @@
if (!msg)
return -1;
+ wpa_printf(MSG_DEBUG, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
+ "no_ack=%d offchanok=%d",
+ freq, wait, no_cck, no_ack, offchanok);
nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
@@ -8269,6 +8398,16 @@
}
+static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
+ return -1;
+ return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
+}
+
+
static void wpa_driver_nl80211_resume(void *priv)
{
struct i802_bss *bss = priv;
@@ -8407,11 +8546,9 @@
MACSTR,
driver->phyname, driver->first_bss.ifname,
MAC2STR(driver->first_bss.addr));
-#ifdef ANDROID_P2P
- if(is_ap_interface(driver->nlmode))
+ if (is_ap_interface(driver->nlmode))
freq = driver->first_bss.freq;
else
-#endif
freq = nl80211_get_assoc_freq(driver);
wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
drv->phyname, freq);
@@ -9016,6 +9153,7 @@
wpa_driver_nl80211_cancel_remain_on_channel,
.probe_req_report = wpa_driver_nl80211_probe_req_report,
.deinit_ap = wpa_driver_nl80211_deinit_ap,
+ .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
.resume = wpa_driver_nl80211_resume,
.send_ft_action = nl80211_send_ft_action,
.signal_monitor = nl80211_signal_monitor,
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index 81a328a..c8916f0 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -651,7 +651,7 @@
os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
- perror("bind(PF_UNIX)");
+ perror("privsep-set-params priv-sock: bind(PF_UNIX)");
close(drv->priv_socket);
drv->priv_socket = -1;
unlink(drv->own_socket_path);
@@ -676,7 +676,7 @@
os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
- perror("bind(PF_UNIX)");
+ perror("privsep-set-params cmd-sock: bind(PF_UNIX)");
close(drv->cmd_socket);
drv->cmd_socket = -1;
unlink(drv->own_cmd_path);
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index 61b75b1..0a9078a 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -2,14 +2,8 @@
* WPA Supplicant - roboswitch driver interface
* Copyright (c) 2008-2009 Jouke Witteveen
*
- * 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 "includes.h"
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 43b30e9..f011651 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1275,7 +1275,7 @@
alen = sizeof(addr_un);
}
if (bind(drv->test_socket, addr, alen) < 0) {
- perror("bind(PF_UNIX)");
+ perror("test-driver-init: bind(PF_UNIX)");
close(drv->test_socket);
if (drv->own_socket_path)
unlink(drv->own_socket_path);
@@ -2252,7 +2252,7 @@
os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
if (bind(drv->test_socket, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ perror("test-driver-attach: bind(PF_UNIX)");
close(drv->test_socket);
unlink(drv->own_socket_path);
os_free(drv->own_socket_path);
@@ -2867,7 +2867,8 @@
if (!drv->p2p)
return -1;
return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent,
- own_interface_addr, force_freq, persistent_group);
+ own_interface_addr, force_freq, persistent_group,
+ NULL, 0, 0);
}
@@ -2912,7 +2913,7 @@
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)
+ 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;
@@ -2933,8 +2934,8 @@
#if 0 /* TODO: WPS IE */
wpa_s->wps->dev.p2p = 1;
- wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
- WPS_REQ_ENROLLEE);
+ 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
@@ -2961,11 +2962,6 @@
break;
case P2P_SCAN_FULL:
break;
- case P2P_SCAN_SPECIFIC:
- social_channels[0] = freq;
- social_channels[1] = 0;
- params.freqs = social_channels;
- break;
case P2P_SCAN_SOCIAL_PLUS_ONE:
social_channels[3] = freq;
params.freqs = social_channels;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 204de34..fd90438 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -584,10 +584,28 @@
del ? "removed" : "added");
if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
- if (del)
+ if (del) {
+ if (drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "WEXT: if_removed "
+ "already set - ignore event");
+ return;
+ }
drv->if_removed = 1;
- else
+ } else {
+ if (if_nametoindex(drv->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Interface %s "
+ "does not exist - ignore "
+ "RTM_NEWLINK",
+ drv->ifname);
+ return;
+ }
+ if (!drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "WEXT: if_removed "
+ "already cleared - ignore event");
+ return;
+ }
drv->if_removed = 0;
+ }
}
wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
@@ -643,6 +661,7 @@
struct wpa_driver_wext_data *drv = ctx;
int attrlen, rta_len;
struct rtattr *attr;
+ char namebuf[IFNAMSIZ];
if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) {
wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
@@ -665,9 +684,25 @@
}
if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
- wpa_printf(MSG_DEBUG, "WEXT: Interface up");
- drv->if_disabled = 0;
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
+ if (if_indextoname(ifi->ifi_index, namebuf) &&
+ linux_iface_up(drv->ioctl_sock, drv->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+ "event since interface %s is down",
+ namebuf);
+ } else if (if_nametoindex(drv->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+ "event since interface %s does not exist",
+ drv->ifname);
+ } else if (drv->if_removed) {
+ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+ "event since interface %s is marked "
+ "removed", drv->ifname);
+ } else {
+ wpa_printf(MSG_DEBUG, "WEXT: Interface up");
+ drv->if_disabled = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
+ }
}
/*
@@ -1566,6 +1601,7 @@
}
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
WPA_DRIVER_CAPA_ENC_WEP104;
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP128;
if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c
index 618db26..e0f0f22 100644
--- a/src/drivers/driver_wired.c
+++ b/src/drivers/driver_wired.c
@@ -3,14 +3,8 @@
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
*
- * 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 "includes.h"
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 4f98fae..74cc55c 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -156,21 +156,25 @@
* @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
* or %NL80211_ATTR_MAC.
*
- * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
- * %NL80222_CMD_NEW_BEACON message)
- * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
- * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
- * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
- * Following attributes are provided for drivers that generate full Beacon
- * and Probe Response frames internally: %NL80211_ATTR_SSID,
+ * @NL80211_CMD_GET_BEACON: (not used)
+ * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface
+ * using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL
+ * attributes. For drivers that generate the beacon and probe responses
+ * internally, the following attributes must be provided: %NL80211_ATTR_IE,
+ * %NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP.
+ * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters
+ * are like for %NL80211_CMD_SET_BEACON, and additionally parameters that
+ * do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL,
+ * %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID,
* %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
* %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
* %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
- * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP,
- * %NL80211_ATTR_IE_ASSOC_RESP.
- * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
- * parameters are like for %NL80211_CMD_SET_BEACON.
- * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ * %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
+ * The channel to use can be set on the interface or be given using the
+ * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs.
+ * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
+ * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
+ * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
*
* @NL80211_CMD_GET_STATION: Get station attributes for station identified by
* %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
@@ -273,6 +277,12 @@
* @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
* NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
*
+ * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC
+ * (for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC
+ * (for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries.
+ *
* @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
* has been changed and provides details of the request information
* that caused the change such as who initiated the regulatory request
@@ -367,6 +377,11 @@
* %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
+ * Background scan period can optionally be
+ * specified in %NL80211_ATTR_BG_SCAN_PERIOD,
+ * if not specified default background scan configuration
+ * in driver is used and if period value is 0, bg scan will be disabled.
+ * This attribute is ignored if driver does not support roam scan.
* It is also sent as an event, with the BSSID and response IEs when the
* connection is established or failed to be established. This can be
* determined by the STATUS_CODE attribute.
@@ -447,6 +462,10 @@
* the frame.
* @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
* backward compatibility.
+ *
+ * @NL80211_CMD_SET_POWER_SAVE: Set powersave, using %NL80211_ATTR_PS_STATE
+ * @NL80211_CMD_GET_POWER_SAVE: Get powersave status in %NL80211_ATTR_PS_STATE
+ *
* @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
* is used to configure connection quality monitoring notification trigger
* levels.
@@ -541,6 +560,11 @@
* @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
* No Acknowledgement Policy should be applied.
*
+ * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
+ * independently of the userspace SME, send this event indicating
+ * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with
+ * %NL80211_ATTR_WIPHY_CHANNEL_TYPE.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -565,8 +589,10 @@
NL80211_CMD_GET_BEACON,
NL80211_CMD_SET_BEACON,
- NL80211_CMD_NEW_BEACON,
- NL80211_CMD_DEL_BEACON,
+ NL80211_CMD_START_AP,
+ NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP,
+ NL80211_CMD_STOP_AP,
+ NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP,
NL80211_CMD_GET_STATION,
NL80211_CMD_SET_STATION,
@@ -680,6 +706,8 @@
NL80211_CMD_SET_NOACK_MAP,
+ NL80211_CMD_CH_SWITCH_NOTIFY,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -753,6 +781,13 @@
* section 7.3.2.25.1, e.g. 0x000FAC04)
* @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
* CCMP keys, each six bytes in little endian
+ * @NL80211_ATTR_KEY_DEFAULT: Flag attribute indicating the key is default key
+ * @NL80211_ATTR_KEY_DEFAULT_MGMT: Flag attribute indicating the key is the
+ * default management key
+ * @NL80211_ATTR_CIPHER_SUITES_PAIRWISE: For crypto settings for connect or
+ * other commands, indicates which pairwise cipher suites are used
+ * @NL80211_ATTR_CIPHER_SUITE_GROUP: For crypto settings for connect or
+ * other commands, indicates which group cipher suite is used
*
* @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
* @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
@@ -988,6 +1023,8 @@
* @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
* acknowledged by the recipient.
*
+ * @NL80211_ATTR_PS_STATE: powersave state, using &enum nl80211_ps_state values.
+ *
* @NL80211_ATTR_CQM: connection quality monitor configuration in a
* nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
*
@@ -1045,7 +1082,7 @@
* flag isn't set, the frame will be rejected. This is also used as an
* nl80211 capability flag.
*
- * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16)
+ * @NL80211_ATTR_BSS_HT_OPMODE: HT operation mode (u16)
*
* @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags
* attributes, specifying what a key should be set as default as.
@@ -1069,10 +1106,10 @@
* indicate which WoW triggers should be enabled. This is also
* used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN
* triggers.
-
+ *
* @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
* cycles, in msecs.
-
+ *
* @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
* sets of attributes to match during scheduled scans. Only BSSs
* that match any of the sets will be reported. These are
@@ -1099,7 +1136,7 @@
* are managed in software: interfaces of these types aren't subject to
* any restrictions in their number or combinations.
*
- * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ * @NL80211_ATTR_REKEY_DATA: nested attribute containing the information
* necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
*
* @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan,
@@ -1166,7 +1203,6 @@
* @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
* &enum nl80211_feature_flags and is advertised in wiphy information.
* @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
- *
* requests while operating in AP-mode.
* This attribute holds a bitmap of the supported protocols for
* offloading (see &enum nl80211_probe_resp_offload_support_attr).
@@ -1193,6 +1229,19 @@
* @NL80211_ATTR_NOACK_MAP: This u16 bitmap contains the No Ack Policy of
* up to 16 TIDs.
*
+ * @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be
+ * used by the drivers which has MLME in firmware and does not have support
+ * to report per station tx/rx activity to free up the staion entry from
+ * the list. This needs to be used when the driver advertises the
+ * capability to timeout the stations.
+ *
+ * @NL80211_ATTR_RX_SIGNAL_DBM: signal strength in dBm (as a 32-bit int);
+ * this attribute is (depending on the driver capabilities) added to
+ * received frames indicated with %NL80211_CMD_FRAME.
+ *
+ * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds
+ * or 0 to disable background scan.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1438,6 +1487,12 @@
NL80211_ATTR_NOACK_MAP,
+ NL80211_ATTR_INACTIVITY_TIMEOUT,
+
+ NL80211_ATTR_RX_SIGNAL_DBM,
+
+ NL80211_ATTR_BG_SCAN_PERIOD,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1475,6 +1530,7 @@
#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
#define NL80211_MAX_SUPP_RATES 32
+#define NL80211_MAX_SUPP_HT_RATES 77
#define NL80211_MAX_SUPP_REG_RULES 32
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
@@ -1484,6 +1540,11 @@
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
+#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10
+
+/* default RSSI threshold for scan results if none specified. */
+#define NL80211_SCAN_RSSI_THOLD_OFF -300
+
/**
* enum nl80211_iftype - (virtual) interface types
*
@@ -1558,6 +1619,8 @@
NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
};
+#define NL80211_STA_FLAG_MAX_OLD_API NL80211_STA_FLAG_TDLS_PEER
+
/**
* struct nl80211_sta_flag_update - station flags mask/set
* @mask: mask of station flags to set
@@ -1656,6 +1719,7 @@
* @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected
* @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
* @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32)
+ * @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64)
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -1679,6 +1743,7 @@
NL80211_STA_INFO_CONNECTED_TIME,
NL80211_STA_INFO_STA_FLAGS,
NL80211_STA_INFO_BEACON_LOSS,
+ NL80211_STA_INFO_T_OFFSET,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -1748,6 +1813,9 @@
* @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
* @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
* @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+ * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as
+ * defined in 802.11ac
+ * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
* @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
* @__NL80211_BAND_ATTR_AFTER_LAST: internal use
*/
@@ -1761,6 +1829,9 @@
NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+ NL80211_BAND_ATTR_VHT_MCS_SET,
+ NL80211_BAND_ATTR_VHT_CAPA,
+
/* keep last */
__NL80211_BAND_ATTR_AFTER_LAST,
NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
@@ -1912,6 +1983,8 @@
* @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
* @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
* only report BSS with matching SSID.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
+ * BSS in scan results. Filtering is turned off if not specified.
* @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
* attribute number currently defined
* @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -1919,7 +1992,8 @@
enum nl80211_sched_scan_match_attr {
__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
- NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+ NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
/* keep last */
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -1927,6 +2001,9 @@
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
};
+/* only for backward compatibility */
+#define NL80211_ATTR_SCHED_SCAN_MATCH_SSID NL80211_SCHED_SCAN_MATCH_ATTR_SSID
+
/**
* enum nl80211_reg_rule_flags - regulatory rule flags
*
@@ -1956,9 +2033,9 @@
* enum nl80211_dfs_regions - regulatory DFS regions
*
* @NL80211_DFS_UNSET: Country has no DFS master region specified
- * @NL80211_DFS_FCC_: Country follows DFS master rules from FCC
- * @NL80211_DFS_FCC_: Country follows DFS master rules from ETSI
- * @NL80211_DFS_JP_: Country follows DFS master rules from JP/MKK/Telec
+ * @NL80211_DFS_FCC: Country follows DFS master rules from FCC
+ * @NL80211_DFS_ETSI: Country follows DFS master rules from ETSI
+ * @NL80211_DFS_JP: Country follows DFS master rules from JP/MKK/Telec
*/
enum nl80211_dfs_regions {
NL80211_DFS_UNSET = 0,
@@ -2046,69 +2123,91 @@
* @__NL80211_MESHCONF_INVALID: internal use
*
* @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
- * millisecond units, used by the Peer Link Open message
+ * millisecond units, used by the Peer Link Open message
*
* @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in
- * millisecond units, used by the peer link management to close a peer link
+ * millisecond units, used by the peer link management to close a peer link
*
* @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
- * millisecond units
+ * millisecond units
*
* @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
- * on this mesh interface
+ * on this mesh interface
*
* @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
- * open retries that can be sent to establish a new peer link instance in a
- * mesh
+ * open retries that can be sent to establish a new peer link instance in a
+ * mesh
*
* @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
- * point.
+ * point.
*
* @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
- * open peer links when we detect compatible mesh peers.
+ * open peer links when we detect compatible mesh peers.
*
* @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
- * containing a PREQ that an MP can send to a particular destination (path
- * target)
+ * containing a PREQ that an MP can send to a particular destination (path
+ * target)
*
* @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
- * (in milliseconds)
+ * (in milliseconds)
*
* @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
- * until giving up on a path discovery (in milliseconds)
+ * until giving up on a path discovery (in milliseconds)
*
* @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
- * points receiving a PREQ shall consider the forwarding information from the
- * root to be valid. (TU = time unit)
+ * points receiving a PREQ shall consider the forwarding information from
+ * the root to be valid. (TU = time unit)
*
* @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
- * TUs) during which an MP can send only one action frame containing a PREQ
- * reference element
+ * TUs) during which an MP can send only one action frame containing a PREQ
+ * reference element
*
* @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
- * that it takes for an HWMP information element to propagate across the mesh
+ * that it takes for an HWMP information element to propagate across the
+ * mesh
*
* @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not
*
* @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
- * source mesh point for path selection elements.
+ * source mesh point for path selection elements.
*
* @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between
- * root announcements are transmitted.
+ * root announcements are transmitted.
*
* @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
- * access to a broader network beyond the MBSS. This is done via Root
- * Announcement frames.
+ * access to a broader network beyond the MBSS. This is done via Root
+ * Announcement frames.
*
* @NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL: The minimum interval of time (in
- * TUs) during which a mesh STA can send only one Action frame containing a
- * PERR element.
+ * TUs) during which a mesh STA can send only one Action frame containing a
+ * PERR element.
*
* @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding
- * or forwarding entity (default is TRUE - forwarding entity)
+ * or forwarding entity (default is TRUE - forwarding entity)
+ *
+ * @NL80211_MESHCONF_RSSI_THRESHOLD: RSSI threshold in dBm. This specifies the
+ * threshold for average signal strength of candidate station to establish
+ * a peer link.
+ *
+ * @NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR: maximum number of neighbors
+ * to synchronize to for 11s default synchronization method
+ * (see 11C.12.2.2)
+ *
+ * @NL80211_MESHCONF_HT_OPMODE: set mesh HT protection mode.
*
* @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
*
+ * @NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT: The time (in TUs) for
+ * which mesh STAs receiving a proactive PREQ shall consider the forwarding
+ * information to the root mesh STA to be valid.
+ *
+ * @NL80211_MESHCONF_HWMP_ROOT_INTERVAL: The interval of time (in TUs) between
+ * proactive PREQs are transmitted.
+ *
+ * @NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL: The minimum interval of time
+ * (in TUs) during which a mesh STA can send only one Action frame
+ * containing a PREQ element for root path confirmation.
+ *
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
*/
enum nl80211_meshconf_params {
@@ -2132,6 +2231,12 @@
NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
NL80211_MESHCONF_FORWARDING,
+ NL80211_MESHCONF_RSSI_THRESHOLD,
+ NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
+ NL80211_MESHCONF_HT_OPMODE,
+ NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
+ NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
+ NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2147,30 +2252,37 @@
* @__NL80211_MESH_SETUP_INVALID: Internal use
*
* @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a
- * vendor specific path selection algorithm or disable it to use the default
- * HWMP.
+ * vendor specific path selection algorithm or disable it to use the
+ * default HWMP.
*
* @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a
- * vendor specific path metric or disable it to use the default Airtime
- * metric.
+ * vendor specific path metric or disable it to use the default Airtime
+ * metric.
*
* @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
- * robust security network ie, or a vendor specific information element that
- * vendors will use to identify the path selection methods and metrics in use.
+ * robust security network ie, or a vendor specific information element
+ * that vendors will use to identify the path selection methods and
+ * metrics in use.
*
* @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication
- * daemon will be authenticating mesh candidates.
+ * daemon will be authenticating mesh candidates.
*
* @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication
- * daemon will be securing peer link frames. AMPE is a secured version of Mesh
- * Peering Management (MPM) and is implemented with the assistance of a
- * userspace daemon. When this flag is set, the kernel will send peer
- * management frames to a userspace daemon that will implement AMPE
- * functionality (security capabilities selection, key confirmation, and key
- * management). When the flag is unset (default), the kernel can autonomously
- * complete (unsecured) mesh peering without the need of a userspace daemon.
+ * daemon will be securing peer link frames. AMPE is a secured version of
+ * Mesh Peering Management (MPM) and is implemented with the assistance of
+ * a userspace daemon. When this flag is set, the kernel will send peer
+ * management frames to a userspace daemon that will implement AMPE
+ * functionality (security capabilities selection, key confirmation, and
+ * key management). When the flag is unset (default), the kernel can
+ * autonomously complete (unsecured) mesh peering without the need of a
+ * userspace daemon.
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC: Enable this option to use a
+ * vendor specific synchronization method or disable it to use the default
+ * neighbor offset synchronization
*
* @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
+ *
* @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
*/
enum nl80211_mesh_setup_params {
@@ -2180,6 +2292,7 @@
NL80211_MESH_SETUP_IE,
NL80211_MESH_SETUP_USERSPACE_AUTH,
NL80211_MESH_SETUP_USERSPACE_AMPE,
+ NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC,
/* keep last */
__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
@@ -2189,7 +2302,7 @@
/**
* enum nl80211_txq_attr - TX queue parameter attributes
* @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
- * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
+ * @NL80211_TXQ_ATTR_AC: AC identifier (NL80211_AC_*)
* @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
* disabled
* @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
@@ -2202,7 +2315,7 @@
*/
enum nl80211_txq_attr {
__NL80211_TXQ_ATTR_INVALID,
- NL80211_TXQ_ATTR_QUEUE,
+ NL80211_TXQ_ATTR_AC,
NL80211_TXQ_ATTR_TXOP,
NL80211_TXQ_ATTR_CWMIN,
NL80211_TXQ_ATTR_CWMAX,
@@ -2213,13 +2326,21 @@
NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
};
-enum nl80211_txq_q {
- NL80211_TXQ_Q_VO,
- NL80211_TXQ_Q_VI,
- NL80211_TXQ_Q_BE,
- NL80211_TXQ_Q_BK
+enum nl80211_ac {
+ NL80211_AC_VO,
+ NL80211_AC_VI,
+ NL80211_AC_BE,
+ NL80211_AC_BK,
+ NL80211_NUM_ACS
};
+/* backward compat */
+#define NL80211_TXQ_ATTR_QUEUE NL80211_TXQ_ATTR_AC
+#define NL80211_TXQ_Q_VO NL80211_AC_VO
+#define NL80211_TXQ_Q_VI NL80211_AC_VI
+#define NL80211_TXQ_Q_BE NL80211_AC_BE
+#define NL80211_TXQ_Q_BK NL80211_AC_BK
+
enum nl80211_channel_type {
NL80211_CHAN_NO_HT,
NL80211_CHAN_HT20,
@@ -2405,12 +2526,15 @@
* 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
+ * in an array of MCS numbers.
* @__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,
/* keep last */
__NL80211_TXRATE_AFTER_LAST,
@@ -2421,12 +2545,19 @@
* enum nl80211_band - Frequency band
* @NL80211_BAND_2GHZ: 2.4 GHz ISM band
* @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
+ * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz)
*/
enum nl80211_band {
NL80211_BAND_2GHZ,
NL80211_BAND_5GHZ,
+ NL80211_BAND_60GHZ,
};
+/**
+ * enum nl80211_ps_state - powersave state
+ * @NL80211_PS_DISABLED: powersave is disabled
+ * @NL80211_PS_ENABLED: powersave is enabled
+ */
enum nl80211_ps_state {
NL80211_PS_DISABLED,
NL80211_PS_ENABLED,
@@ -2465,10 +2596,14 @@
* configured threshold
* @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
* configured threshold
+ * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
+ * (Note that deauth/disassoc will still follow if the AP is not
+ * available. This event might get used as roaming event, etc.)
*/
enum nl80211_cqm_rssi_threshold_event {
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+ NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
};
@@ -2796,10 +2931,13 @@
* TX status to the socket error queue when requested with the
* socket option.
* @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates.
+ * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up
+ * the connected inactive stations in AP mode.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
NL80211_FEATURE_HT_IBSS = 1 << 1,
+ NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
};
/**
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index af0a29a..360193a 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -60,7 +60,7 @@
EAP_TYPE_PSK = 47 /* RFC 4764 */,
EAP_TYPE_SAKE = 48 /* RFC 4763 */,
EAP_TYPE_IKEV2 = 49 /* RFC 5106 */,
- EAP_TYPE_AKA_PRIME = 50 /* draft-arkko-eap-aka-kdf-10.txt */,
+ EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */,
EAP_TYPE_GPSK = 51 /* RFC 5433 */,
EAP_TYPE_PWD = 52 /* RFC 5931 */,
EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index 5b6bf3c..7d6e6b8 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -8,70 +8,76 @@
#include "includes.h"
#include "common.h"
+#include "crypto/sha256.h"
+#include "crypto/crypto.h"
#include "eap_defs.h"
#include "eap_pwd_common.h"
/* The random function H(x) = HMAC-SHA256(0^32, x) */
-void H_Init(HMAC_CTX *ctx)
+struct crypto_hash * eap_pwd_h_init(void)
{
- u8 allzero[SHA256_DIGEST_LENGTH];
-
- os_memset(allzero, 0, SHA256_DIGEST_LENGTH);
- HMAC_Init(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256());
+ u8 allzero[SHA256_MAC_LEN];
+ os_memset(allzero, 0, SHA256_MAC_LEN);
+ return crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256, allzero,
+ SHA256_MAC_LEN);
}
-void H_Update(HMAC_CTX *ctx, const u8 *data, int len)
+void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len)
{
- HMAC_Update(ctx, data, len);
+ crypto_hash_update(hash, data, len);
}
-void H_Final(HMAC_CTX *ctx, u8 *digest)
+void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest)
{
- unsigned int mdlen = SHA256_DIGEST_LENGTH;
-
- HMAC_Final(ctx, digest, &mdlen);
- HMAC_CTX_cleanup(ctx);
+ size_t len = SHA256_MAC_LEN;
+ crypto_hash_finish(hash, digest, &len);
}
/* a counter-based KDF based on NIST SP800-108 */
-void eap_pwd_kdf(u8 *key, int keylen, u8 *label, int labellen,
- u8 *result, int resultbitlen)
+static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label,
+ size_t labellen, u8 *result, size_t resultbitlen)
{
- HMAC_CTX hctx;
- unsigned char digest[SHA256_DIGEST_LENGTH];
+ struct crypto_hash *hash;
+ u8 digest[SHA256_MAC_LEN];
u16 i, ctr, L;
- int resultbytelen, len = 0;
- unsigned int mdlen = SHA256_DIGEST_LENGTH;
- unsigned char mask = 0xff;
+ size_t resultbytelen, len = 0, mdlen;
- resultbytelen = (resultbitlen + 7)/8;
+ resultbytelen = (resultbitlen + 7) / 8;
ctr = 0;
L = htons(resultbitlen);
while (len < resultbytelen) {
- ctr++; i = htons(ctr);
- HMAC_Init(&hctx, key, keylen, EVP_sha256());
+ ctr++;
+ i = htons(ctr);
+ hash = crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256,
+ key, keylen);
+ if (hash == NULL)
+ return -1;
if (ctr > 1)
- HMAC_Update(&hctx, digest, mdlen);
- HMAC_Update(&hctx, (u8 *) &i, sizeof(u16));
- HMAC_Update(&hctx, label, labellen);
- HMAC_Update(&hctx, (u8 *) &L, sizeof(u16));
- HMAC_Final(&hctx, digest, &mdlen);
- if ((len + (int) mdlen) > resultbytelen)
+ crypto_hash_update(hash, digest, SHA256_MAC_LEN);
+ crypto_hash_update(hash, (u8 *) &i, sizeof(u16));
+ crypto_hash_update(hash, label, labellen);
+ crypto_hash_update(hash, (u8 *) &L, sizeof(u16));
+ mdlen = SHA256_MAC_LEN;
+ if (crypto_hash_finish(hash, digest, &mdlen) < 0)
+ return -1;
+ if ((len + mdlen) > resultbytelen)
os_memcpy(result + len, digest, resultbytelen - len);
else
os_memcpy(result + len, digest, mdlen);
len += mdlen;
- HMAC_CTX_cleanup(&hctx);
}
/* since we're expanding to a bit length, mask off the excess */
if (resultbitlen % 8) {
+ u8 mask = 0xff;
mask <<= (8 - (resultbitlen % 8));
result[resultbytelen - 1] &= mask;
}
+
+ return 0;
}
@@ -85,9 +91,10 @@
u8 *id_peer, int id_peer_len, u8 *token)
{
BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
- HMAC_CTX ctx;
- unsigned char pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr;
- int nid, is_odd, primebitlen, primebytelen, ret = 0;
+ struct crypto_hash *hash;
+ unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
+ int nid, is_odd, ret = 0;
+ size_t primebytelen, primebitlen;
switch (num) { /* from IANA registry for IKE D-H groups */
case 19:
@@ -154,7 +161,7 @@
os_memset(prfbuf, 0, primebytelen);
ctr = 0;
while (1) {
- if (ctr > 10) {
+ if (ctr > 30) {
wpa_printf(MSG_INFO, "EAP-pwd: unable to find random "
"point on curve for group %d, something's "
"fishy", num);
@@ -167,20 +174,23 @@
* pwd-seed = H(token | peer-id | server-id | password |
* counter)
*/
- H_Init(&ctx);
- H_Update(&ctx, token, sizeof(u32));
- H_Update(&ctx, id_peer, id_peer_len);
- H_Update(&ctx, id_server, id_server_len);
- H_Update(&ctx, password, password_len);
- H_Update(&ctx, &ctr, sizeof(ctr));
- H_Final(&ctx, pwe_digest);
+ hash = eap_pwd_h_init();
+ if (hash == NULL)
+ goto fail;
+ eap_pwd_h_update(hash, token, sizeof(u32));
+ eap_pwd_h_update(hash, id_peer, id_peer_len);
+ eap_pwd_h_update(hash, id_server, id_server_len);
+ eap_pwd_h_update(hash, password, password_len);
+ eap_pwd_h_update(hash, &ctr, sizeof(ctr));
+ eap_pwd_h_final(hash, pwe_digest);
- BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd);
+ BN_bin2bn(pwe_digest, SHA256_MAC_LEN, rnd);
- eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH,
- (unsigned char *) "EAP-pwd Hunting And Pecking",
- os_strlen("EAP-pwd Hunting And Pecking"),
- prfbuf, primebitlen);
+ if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN,
+ (u8 *) "EAP-pwd Hunting And Pecking",
+ os_strlen("EAP-pwd Hunting And Pecking"),
+ prfbuf, primebitlen) < 0)
+ goto fail;
BN_bin2bn(prfbuf, primebytelen, x_candidate);
@@ -252,11 +262,13 @@
if (0) {
fail:
EC_GROUP_free(grp->group);
+ grp->group = NULL;
EC_POINT_free(grp->pwe);
+ grp->pwe = NULL;
BN_free(grp->order);
+ grp->order = NULL;
BN_free(grp->prime);
- os_free(grp);
- grp = NULL;
+ grp->prime = NULL;
ret = 1;
}
/* cleanliness and order.... */
@@ -274,9 +286,9 @@
u8 *confirm_peer, u8 *confirm_server,
u32 *ciphersuite, u8 *msk, u8 *emsk)
{
- HMAC_CTX ctx;
- u8 mk[SHA256_DIGEST_LENGTH], *cruft;
- u8 session_id[SHA256_DIGEST_LENGTH + 1];
+ struct crypto_hash *hash;
+ u8 mk[SHA256_MAC_LEN], *cruft;
+ u8 session_id[SHA256_MAC_LEN + 1];
u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
int offset;
@@ -288,37 +300,46 @@
* scal_s)
*/
session_id[0] = EAP_TYPE_PWD;
- H_Init(&ctx);
- H_Update(&ctx, (u8 *)ciphersuite, sizeof(u32));
+ hash = eap_pwd_h_init();
+ if (hash == NULL) {
+ os_free(cruft);
+ return -1;
+ }
+ eap_pwd_h_update(hash, (u8 *) ciphersuite, sizeof(u32));
offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar);
os_memset(cruft, 0, BN_num_bytes(grp->prime));
BN_bn2bin(peer_scalar, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(grp->order));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar);
os_memset(cruft, 0, BN_num_bytes(grp->prime));
BN_bn2bin(server_scalar, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(grp->order));
- H_Final(&ctx, &session_id[1]);
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
+ eap_pwd_h_final(hash, &session_id[1]);
/* then compute MK = H(k | confirm-peer | confirm-server) */
- H_Init(&ctx);
+ hash = eap_pwd_h_init();
+ if (hash == NULL) {
+ os_free(cruft);
+ return -1;
+ }
offset = BN_num_bytes(grp->prime) - BN_num_bytes(k);
os_memset(cruft, 0, BN_num_bytes(grp->prime));
BN_bn2bin(k, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(grp->prime));
- H_Update(&ctx, confirm_peer, SHA256_DIGEST_LENGTH);
- H_Update(&ctx, confirm_server, SHA256_DIGEST_LENGTH);
- H_Final(&ctx, mk);
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->prime));
+ os_free(cruft);
+ eap_pwd_h_update(hash, confirm_peer, SHA256_MAC_LEN);
+ eap_pwd_h_update(hash, confirm_server, SHA256_MAC_LEN);
+ eap_pwd_h_final(hash, mk);
/* stretch the mk with the session-id to get MSK | EMSK */
- eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH,
- session_id, SHA256_DIGEST_LENGTH+1,
- msk_emsk, (EAP_MSK_LEN + EAP_EMSK_LEN) * 8);
+ if (eap_pwd_kdf(mk, SHA256_MAC_LEN,
+ session_id, SHA256_MAC_LEN + 1,
+ msk_emsk, (EAP_MSK_LEN + EAP_EMSK_LEN) * 8) < 0) {
+ return -1;
+ }
os_memcpy(msk, msk_emsk, EAP_MSK_LEN);
os_memcpy(emsk, msk_emsk + EAP_MSK_LEN, EAP_EMSK_LEN);
- os_free(cruft);
-
return 1;
}
diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h
index 358d008..816e58c 100644
--- a/src/eap_common/eap_pwd_common.h
+++ b/src/eap_common/eap_pwd_common.h
@@ -10,10 +10,8 @@
#define EAP_PWD_COMMON_H
#include <openssl/bn.h>
-#include <openssl/sha.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
-#include <openssl/hmac.h>
/*
* definition of a finite cyclic group
@@ -62,8 +60,8 @@
int, u8 *);
int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, BIGNUM *, BIGNUM *,
u8 *, u8 *, u32 *, u8 *, u8 *);
-void H_Init(HMAC_CTX *);
-void H_Update(HMAC_CTX *, const u8 *, int);
-void H_Final(HMAC_CTX *, u8 *);
+struct crypto_hash * eap_pwd_h_init(void);
+void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len);
+void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest);
#endif /* EAP_PWD_COMMON_H */
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 6a88589..8b43be4 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-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -81,6 +81,16 @@
}
+static void eap_notify_status(struct eap_sm *sm, const char *status,
+ const char *parameter)
+{
+ wpa_printf(MSG_DEBUG, "EAP: Status notification: %s (param=%s)",
+ status, parameter);
+ if (sm->eapol_cb->notify_status)
+ sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter);
+}
+
+
static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
{
if (sm->m == NULL || sm->eap_method_priv == NULL)
@@ -213,6 +223,7 @@
{
int reinit;
EapType method;
+ const struct eap_method *eap_method;
SM_ENTRY(EAP, GET_METHOD);
@@ -221,18 +232,24 @@
else
method = sm->reqMethod;
+ eap_method = eap_peer_get_eap_method(sm->reqVendor, method);
+
if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
sm->reqVendor, method);
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"vendor=%u method=%u -> NAK",
sm->reqVendor, method);
+ eap_notify_status(sm, "refuse proposed method",
+ eap_method ? eap_method->name : "unknown");
goto nak;
}
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"vendor=%u method=%u", sm->reqVendor, method);
+ eap_notify_status(sm, "accept proposed method",
+ eap_method ? eap_method->name : "unknown");
/*
* RFC 4137 does not define specific operation for fast
* re-authentication (session resumption). The design here is to allow
@@ -256,7 +273,7 @@
sm->selectedMethod = sm->reqMethod;
if (sm->m == NULL)
- sm->m = eap_peer_get_eap_method(sm->reqVendor, method);
+ sm->m = eap_method;
if (!sm->m) {
wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
"vendor %d method %d",
@@ -938,7 +955,7 @@
static int eap_sm_imsi_identity(struct eap_sm *sm,
struct eap_peer_config *conf)
{
- int aka = 0;
+ enum { EAP_SM_SIM, EAP_SM_AKA, EAP_SM_AKA_PRIME } method = EAP_SM_SIM;
char imsi[100];
size_t imsi_len;
struct eap_method_type *m = conf->eap_methods;
@@ -966,8 +983,14 @@
for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
m[i].method != EAP_TYPE_NONE); i++) {
if (m[i].vendor == EAP_VENDOR_IETF &&
+ m[i].method == EAP_TYPE_AKA_PRIME) {
+ method = EAP_SM_AKA_PRIME;
+ break;
+ }
+
+ if (m[i].vendor == EAP_VENDOR_IETF &&
m[i].method == EAP_TYPE_AKA) {
- aka = 1;
+ method = EAP_SM_AKA;
break;
}
}
@@ -980,7 +1003,17 @@
return -1;
}
- conf->identity[0] = aka ? '0' : '1';
+ switch (method) {
+ case EAP_SM_SIM:
+ conf->identity[0] = '1';
+ break;
+ case EAP_SM_AKA:
+ conf->identity[0] = '0';
+ break;
+ case EAP_SM_AKA_PRIME:
+ conf->identity[0] = '6';
+ break;
+ }
os_memcpy(conf->identity + 1, imsi, imsi_len);
conf->identity_len = 1 + imsi_len;
@@ -1219,10 +1252,12 @@
break;
case EAP_CODE_SUCCESS:
wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
+ eap_notify_status(sm, "completion", "success");
sm->rxSuccess = TRUE;
break;
case EAP_CODE_FAILURE:
wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
+ eap_notify_status(sm, "completion", "failure");
sm->rxFailure = TRUE;
break;
default:
@@ -1240,6 +1275,10 @@
char *hash_hex = NULL;
switch (ev) {
+ case TLS_CERT_CHAIN_SUCCESS:
+ eap_notify_status(sm, "remote certificate verification",
+ "success");
+ break;
case TLS_CERT_CHAIN_FAILURE:
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
"reason=%d depth=%d subject='%s' err='%s'",
@@ -1247,6 +1286,8 @@
data->cert_fail.depth,
data->cert_fail.subject,
data->cert_fail.reason_txt);
+ eap_notify_status(sm, "remote certificate verification",
+ data->cert_fail.reason_txt);
break;
case TLS_PEER_CERTIFICATE:
if (!sm->eapol_cb->notify_cert)
@@ -1267,6 +1308,14 @@
data->peer_cert.subject,
hash_hex, data->peer_cert.cert);
break;
+ case TLS_ALERT:
+ if (data->alert.is_local)
+ eap_notify_status(sm, "local TLS alert",
+ data->alert.description);
+ else
+ eap_notify_status(sm, "remote TLS alert",
+ data->alert.description);
+ break;
}
os_free(hash_hex);
@@ -1321,6 +1370,13 @@
return NULL;
}
+ sm->ssl_ctx2 = tls_init(&tlsconf);
+ if (sm->ssl_ctx2 == NULL) {
+ wpa_printf(MSG_INFO, "SSL: Failed to initialize TLS "
+ "context (2).");
+ /* Run without separate TLS context within TLS tunnel */
+ }
+
return sm;
}
@@ -1338,6 +1394,8 @@
return;
eap_deinit_prev_method(sm, "EAP deinit");
eap_sm_abort(sm);
+ if (sm->ssl_ctx2)
+ tls_deinit(sm->ssl_ctx2);
tls_deinit(sm->ssl_ctx);
os_free(sm);
}
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index b95a285..6e87475 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -226,6 +226,15 @@
*/
void (*notify_cert)(void *ctx, int depth, const char *subject,
const char *cert_hash, const struct wpabuf *cert);
+
+ /**
+ * notify_status - Notification of the current EAP state
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @status: Step in the process of EAP authentication
+ * @parameter: Step-specific parameter, e.g., EAP method name
+ */
+ void (*notify_status)(void *ctx, const char *status,
+ const char *parameter);
};
/**
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 7e37e44..1cec4d8 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -1,6 +1,6 @@
/*
- * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -229,19 +229,19 @@
static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
{
- if (id & CLEAR_PSEUDONYM) {
+ if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
}
- if (id & CLEAR_REAUTH_ID) {
+ if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
os_free(data->reauth_id);
data->reauth_id = NULL;
data->reauth_id_len = 0;
}
- if (id & CLEAR_EAP_ID) {
+ if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id");
os_free(data->last_eap_identity);
data->last_eap_identity = NULL;
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 06d6db6..3318b81 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -317,6 +317,7 @@
void *msg_ctx;
void *scard_ctx;
void *ssl_ctx;
+ void *ssl_ctx2;
unsigned int workaround;
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 37e9234..267d0a5 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "crypto/sha256.h"
#include "eap_peer/eap_i.h"
#include "eap_common/eap_pwd_common.h"
@@ -459,10 +460,10 @@
const u8 *payload, size_t payload_len)
{
BIGNUM *x = NULL, *y = NULL;
- HMAC_CTX ctx;
+ struct crypto_hash *hash;
u32 cs;
u16 grp;
- u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+ u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
int offset;
/*
@@ -489,7 +490,9 @@
* server's commit is H(k | server_element | server_scalar |
* peer_element | peer_scalar | ciphersuite)
*/
- H_Init(&ctx);
+ hash = eap_pwd_h_init();
+ if (hash == NULL)
+ goto fin;
/*
* zero the memory each time because this is mod prime math and some
@@ -498,7 +501,7 @@
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
BN_bn2bin(data->k, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* server element: x, y */
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -511,18 +514,18 @@
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
BN_bn2bin(x, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
BN_bn2bin(y, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* server scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->order) -
BN_num_bytes(data->server_scalar);
BN_bn2bin(data->server_scalar, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
/* my element: x, y */
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -536,27 +539,27 @@
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
BN_bn2bin(x, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
BN_bn2bin(y, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* my scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->order) -
BN_num_bytes(data->my_scalar);
BN_bn2bin(data->my_scalar, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
/* the ciphersuite */
- H_Update(&ctx, (u8 *) &cs, sizeof(u32));
+ eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
/* random function fin */
- H_Final(&ctx, conf);
+ eap_pwd_h_final(hash, conf);
ptr = (u8 *) payload;
- if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
+ if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
goto fin;
}
@@ -568,13 +571,15 @@
* H(k | peer_element | peer_scalar | server_element | server_scalar |
* ciphersuite)
*/
- H_Init(&ctx);
+ hash = eap_pwd_h_init();
+ if (hash == NULL)
+ goto fin;
/* k */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
BN_bn2bin(data->k, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* my element */
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -587,18 +592,18 @@
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
BN_bn2bin(x, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
BN_bn2bin(y, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* my scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->order) -
BN_num_bytes(data->my_scalar);
BN_bn2bin(data->my_scalar, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
/* server element: x, y */
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -611,24 +616,24 @@
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
BN_bn2bin(x, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
BN_bn2bin(y, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* server scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->order) -
BN_num_bytes(data->server_scalar);
BN_bn2bin(data->server_scalar, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
/* the ciphersuite */
- H_Update(&ctx, (u8 *) &cs, sizeof(u32));
+ eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
/* all done */
- H_Final(&ctx, conf);
+ eap_pwd_h_final(hash, conf);
if (compute_keys(data->grp, data->bnctx, data->k,
data->my_scalar, data->server_scalar, conf, ptr,
@@ -638,11 +643,11 @@
goto fin;
}
- data->outbuf = wpabuf_alloc(SHA256_DIGEST_LENGTH);
+ data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
if (data->outbuf == NULL)
goto fin;
- wpabuf_put_data(data->outbuf, conf, SHA256_DIGEST_LENGTH);
+ wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
fin:
os_free(cruft);
@@ -725,6 +730,7 @@
*/
if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
wpabuf_free(data->outbuf);
+ data->outbuf = NULL;
data->out_frag_pos = 0;
}
wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes",
@@ -856,8 +862,11 @@
/*
* if we're not fragmenting then there's no need to carry this around
*/
- if (data->out_frag_pos == 0)
+ if (data->out_frag_pos == 0) {
wpabuf_free(data->outbuf);
+ data->outbuf = NULL;
+ data->out_frag_pos = 0;
+ }
return resp;
}
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index a3067fa..ed52fb6 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -21,6 +21,7 @@
struct eap_tls_data {
struct eap_ssl_data ssl;
u8 *key_data;
+ void *ssl_ctx;
};
@@ -40,6 +41,9 @@
if (data == NULL)
return NULL;
+ data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+ sm->ssl_ctx;
+
if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_deinit(sm, data);
@@ -165,7 +169,7 @@
return eap_tls_failure(sm, data, ret, res, resp, id);
}
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
+ if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
eap_tls_success(sm, data, ret);
if (res == 1) {
@@ -180,7 +184,7 @@
static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
- return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
+ return tls_connection_established(data->ssl_ctx, data->ssl.conn);
}
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 52549f4..69e83d9 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -1,6 +1,6 @@
/*
* EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -136,14 +136,14 @@
{
int res;
- data->conn = tls_connection_init(sm->ssl_ctx);
+ data->conn = tls_connection_init(data->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
"connection");
return -1;
}
- res = tls_connection_set_params(sm->ssl_ctx, data->conn, params);
+ res = tls_connection_set_params(data->ssl_ctx, data->conn, params);
if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
/*
* At this point with the pkcs11 engine the PIN might be wrong.
@@ -162,13 +162,13 @@
config->pin = NULL;
eap_sm_request_pin(sm);
sm->ignore = TRUE;
- tls_connection_deinit(sm->ssl_ctx, data->conn);
+ tls_connection_deinit(data->ssl_ctx, data->conn);
data->conn = NULL;
return -1;
} else if (res) {
wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
"parameters");
- tls_connection_deinit(sm->ssl_ctx, data->conn);
+ tls_connection_deinit(data->ssl_ctx, data->conn);
data->conn = NULL;
return -1;
}
@@ -197,6 +197,8 @@
data->eap = sm;
data->phase2 = sm->init_phase2;
+ data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+ sm->ssl_ctx;
if (eap_tls_params_from_conf(sm, data, ¶ms, config, data->phase2) <
0)
return -1;
@@ -234,7 +236,7 @@
*/
void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
{
- tls_connection_deinit(sm->ssl_ctx, data->conn);
+ tls_connection_deinit(data->ssl_ctx, data->conn);
eap_peer_tls_reset_input(data);
eap_peer_tls_reset_output(data);
}
@@ -265,8 +267,8 @@
return NULL;
/* First, try to use TLS library function for PRF, if available. */
- if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
- 0)
+ if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len)
+ == 0)
return out;
/*
@@ -274,7 +276,7 @@
* session parameters and use an internal implementation of TLS PRF to
* derive the key.
*/
- if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys))
goto fail;
if (keys.client_random == NULL || keys.server_random == NULL ||
@@ -441,14 +443,14 @@
WPA_ASSERT(data->tls_out == NULL);
}
appl_data = NULL;
- data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn,
+ data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn,
msg, &appl_data);
eap_peer_tls_reset_input(data);
if (appl_data &&
- tls_connection_established(sm->ssl_ctx, data->conn) &&
- !tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+ tls_connection_established(data->ssl_ctx, data->conn) &&
+ !tls_connection_get_failed(data->ssl_ctx, data->conn)) {
wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data",
appl_data);
*out_data = appl_data;
@@ -616,7 +618,7 @@
return -1;
}
- if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+ if (tls_connection_get_failed(data->ssl_ctx, data->conn)) {
/* TLS processing has failed - return error */
wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
"report error");
@@ -675,7 +677,7 @@
{
eap_peer_tls_reset_input(data);
eap_peer_tls_reset_output(data);
- return tls_connection_shutdown(sm->ssl_ctx, data->conn);
+ return tls_connection_shutdown(data->ssl_ctx, data->conn);
}
@@ -694,7 +696,8 @@
char name[128];
int len = 0, ret;
- if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) {
+ if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0)
+ {
ret = os_snprintf(buf + len, buflen - len,
"EAP TLS cipher=%s\n", name);
if (ret < 0 || (size_t) ret >= buflen - len)
@@ -741,7 +744,7 @@
size_t left;
unsigned int tls_msg_len;
- if (tls_get_errors(sm->ssl_ctx)) {
+ if (tls_get_errors(data->ssl_ctx)) {
wpa_printf(MSG_INFO, "SSL: TLS errors detected");
ret->ignore = TRUE;
return NULL;
@@ -849,7 +852,7 @@
if (msg == NULL)
return need_more_input ? 1 : -1;
- *in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg);
+ *in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg);
eap_peer_tls_reset_input(data);
if (*in_decrypted == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data");
@@ -877,8 +880,8 @@
{
if (in_data) {
eap_peer_tls_reset_output(data);
- data->tls_out = tls_connection_encrypt(sm->ssl_ctx, data->conn,
- in_data);
+ data->tls_out = tls_connection_encrypt(data->ssl_ctx,
+ data->conn, in_data);
if (data->tls_out == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 "
"data (in_len=%lu)",
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index 7426467..771385b 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -1,6 +1,6 @@
/*
* EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -63,6 +63,11 @@
* eap - EAP state machine allocated with eap_peer_sm_init()
*/
struct eap_sm *eap;
+
+ /**
+ * ssl_ctx - TLS library context to use for the connection
+ */
+ void *ssl_ctx;
};
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 0204ba2..e09f5e5 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -435,7 +435,6 @@
"implicit challenge");
return -1;
}
- peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
RADIUS_VENDOR_ID_MICROSOFT, 1,
@@ -448,7 +447,14 @@
data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN];
*pos++ = data->ident;
*pos++ = 0; /* Flags */
- os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
+ if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) {
+ os_free(challenge);
+ wpabuf_free(msg);
+ wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get "
+ "random data for peer challenge");
+ return -1;
+ }
+ peer_challenge = pos;
pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
os_memset(pos, 0, 8); /* Reserved, must be zero */
pos += 8;
@@ -456,6 +462,7 @@
password_len, pwhash, challenge,
peer_challenge, pos, data->auth_response,
data->master_key)) {
+ os_free(challenge);
wpabuf_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
"response");
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index 4473b90..d007a57 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -1,6 +1,6 @@
/*
* EAP-WSC peer for Wi-Fi Protected Setup
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2009, 2012, 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,8 @@
struct wps_context *wps;
struct wps_credential new_ap_settings;
int res;
+ u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
+ int nfc = 0;
wps = sm->wps;
if (wps == NULL) {
@@ -184,13 +186,26 @@
while (*pos != '\0' && *pos != ' ')
pos++;
cfg.pin_len = pos - (const char *) cfg.pin;
+ if (cfg.pin_len >= WPS_OOB_DEVICE_PASSWORD_MIN_LEN * 2 &&
+ cfg.pin_len <= WPS_OOB_DEVICE_PASSWORD_LEN * 2 &&
+ hexstr2bin((const char *) cfg.pin, dev_pw,
+ cfg.pin_len / 2) == 0) {
+ /* Convert OOB Device Password to binary */
+ cfg.pin = dev_pw;
+ cfg.pin_len /= 2;
+ }
+ if (cfg.pin_len == 6 && os_strncmp(pos, "nfc-pw", 6) == 0) {
+ cfg.pin = NULL;
+ cfg.pin_len = 0;
+ nfc = 1;
+ }
} else {
pos = os_strstr(phase1, "pbc=1");
if (pos)
cfg.pbc = 1;
}
- if (cfg.pin == NULL && !cfg.pbc) {
+ if (cfg.pin == NULL && !cfg.pbc && !nfc) {
wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
"configuration data");
os_free(data);
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 135c02b..9cd5509 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -1,6 +1,6 @@
/*
- * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
- * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
+ * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
+ * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -266,8 +266,18 @@
EAP_AKA_SUBTYPE_IDENTITY);
if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
sm->identity_len)) {
- wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
- eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
+ if (sm->identity_len > 0 &&
+ (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
+ sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) {
+ /* Reauth id may have expired - try fullauth */
+ wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0,
+ NULL, 0);
+ } else {
+ wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0,
+ NULL, 0);
+ }
} else {
/*
* RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
@@ -292,12 +302,23 @@
const u8 *nonce_s)
{
os_free(data->next_pseudonym);
- data->next_pseudonym =
- eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
+ if (nonce_s == NULL) {
+ data->next_pseudonym =
+ eap_sim_db_get_next_pseudonym(
+ sm->eap_sim_db_priv,
+ data->eap_method == EAP_TYPE_AKA_PRIME ?
+ EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
+ } else {
+ /* Do not update pseudonym during re-authentication */
+ data->next_pseudonym = NULL;
+ }
os_free(data->next_reauth_id);
if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
data->next_reauth_id =
- eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1);
+ eap_sim_db_get_next_reauth_id(
+ sm->eap_sim_db_priv,
+ data->eap_method == EAP_TYPE_AKA_PRIME ?
+ EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
} else {
wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
"count exceeded - force full authentication");
@@ -615,7 +636,8 @@
identity = data->reauth->identity;
identity_len = data->reauth->identity_len;
} else if (sm->identity && sm->identity_len > 0 &&
- sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
+ (sm->identity[0] == EAP_AKA_PERMANENT_PREFIX ||
+ sm->identity[0] == EAP_AKA_PRIME_PERMANENT_PREFIX)) {
identity = sm->identity;
identity_len = sm->identity_len;
} else {
@@ -731,7 +753,7 @@
sm->identity, identity_len);
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
- eap_aka_prime_derive_keys(identity, identity_len, data->ik,
+ eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik,
data->ck, data->k_encr, data->k_aut,
data->k_re, data->msk, data->emsk);
} else {
@@ -1017,11 +1039,6 @@
identity_len = id2_len;
}
- if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
- identity_len, data->next_pseudonym);
- data->next_pseudonym = NULL;
- }
if (data->next_reauth_id) {
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 6c47dee..b61061b 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "crypto/sha256.h"
#include "eap_server/eap_i.h"
#include "eap_common/eap_pwd_common.h"
@@ -40,7 +41,7 @@
EC_POINT *my_element;
EC_POINT *peer_element;
- u8 my_confirm[SHA256_DIGEST_LENGTH];
+ u8 my_confirm[SHA256_MAC_LEN];
u8 msk[EAP_MSK_LEN];
u8 emsk[EAP_EMSK_LEN];
@@ -288,8 +289,8 @@
struct eap_pwd_data *data, u8 id)
{
BIGNUM *x = NULL, *y = NULL;
- HMAC_CTX ctx;
- u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+ struct crypto_hash *hash;
+ u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
u16 grp;
int offset;
@@ -313,7 +314,9 @@
* commit is H(k | server_element | server_scalar | peer_element |
* peer_scalar | ciphersuite)
*/
- H_Init(&ctx);
+ hash = eap_pwd_h_init();
+ if (hash == NULL)
+ goto fin;
/*
* Zero the memory each time because this is mod prime math and some
@@ -324,7 +327,7 @@
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
BN_bn2bin(data->k, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* server element: x, y */
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -338,18 +341,18 @@
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
BN_bn2bin(x, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
BN_bn2bin(y, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* server scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->order) -
BN_num_bytes(data->my_scalar);
BN_bn2bin(data->my_scalar, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
/* peer element: x, y */
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -363,18 +366,18 @@
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
BN_bn2bin(x, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
BN_bn2bin(y, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* peer scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->order) -
BN_num_bytes(data->peer_scalar);
BN_bn2bin(data->peer_scalar, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
/* ciphersuite */
grp = htons(data->group_num);
@@ -386,17 +389,17 @@
ptr += sizeof(u8);
*ptr = EAP_PWD_DEFAULT_PRF;
ptr += sizeof(u8);
- H_Update(&ctx, cruft, ptr-cruft);
+ eap_pwd_h_update(hash, cruft, ptr - cruft);
/* all done with the random function */
- H_Final(&ctx, conf);
- os_memcpy(data->my_confirm, conf, SHA256_DIGEST_LENGTH);
+ eap_pwd_h_final(hash, conf);
+ os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
- data->outbuf = wpabuf_alloc(SHA256_DIGEST_LENGTH);
+ data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
if (data->outbuf == NULL)
goto fin;
- wpabuf_put_data(data->outbuf, conf, SHA256_DIGEST_LENGTH);
+ wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
fin:
os_free(cruft);
@@ -404,8 +407,6 @@
BN_free(y);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
-
- return;
}
@@ -735,10 +736,10 @@
const u8 *payload, size_t payload_len)
{
BIGNUM *x = NULL, *y = NULL;
- HMAC_CTX ctx;
+ struct crypto_hash *hash;
u32 cs;
u16 grp;
- u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+ u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
int offset;
/* build up the ciphersuite: group | random_function | prf */
@@ -761,13 +762,15 @@
* commit is H(k | peer_element | peer_scalar | server_element |
* server_scalar | ciphersuite)
*/
- H_Init(&ctx);
+ hash = eap_pwd_h_init();
+ if (hash == NULL)
+ goto fin;
/* k */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
BN_bn2bin(data->k, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* peer element: x, y */
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -780,18 +783,18 @@
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
BN_bn2bin(x, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
BN_bn2bin(y, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* peer scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->order) -
BN_num_bytes(data->peer_scalar);
BN_bn2bin(data->peer_scalar, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
/* server element: x, y */
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -805,28 +808,28 @@
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
BN_bn2bin(x, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
BN_bn2bin(y, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
/* server scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
offset = BN_num_bytes(data->grp->order) -
BN_num_bytes(data->my_scalar);
BN_bn2bin(data->my_scalar, cruft + offset);
- H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+ eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
/* ciphersuite */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- H_Update(&ctx, (u8 *)&cs, sizeof(u32));
+ eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
/* all done */
- H_Final(&ctx, conf);
+ eap_pwd_h_final(hash, conf);
ptr = (u8 *) payload;
- if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
+ if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
"verify");
goto fin;
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index f49f70e..6658d9c 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -107,8 +107,17 @@
EAP_SIM_SUBTYPE_START);
if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
sm->identity_len)) {
- wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
- eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
+ if (sm->identity_len > 0 &&
+ sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
+ /* Reauth id may have expired - try fullauth */
+ wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0,
+ NULL, 0);
+ } else {
+ wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0,
+ NULL, 0);
+ }
} else {
/*
* RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
@@ -131,12 +140,19 @@
const u8 *nonce_s)
{
os_free(data->next_pseudonym);
- data->next_pseudonym =
- eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0);
+ if (nonce_s == NULL) {
+ data->next_pseudonym =
+ eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv,
+ EAP_SIM_DB_SIM);
+ } else {
+ /* Do not update pseudonym during re-authentication */
+ data->next_pseudonym = NULL;
+ }
os_free(data->next_reauth_id);
if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
data->next_reauth_id =
- eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0);
+ eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv,
+ EAP_SIM_DB_SIM);
} else {
wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
"count exceeded - force full authentication");
@@ -616,11 +632,6 @@
identity_len = id2_len;
}
- if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
- identity_len, data->next_pseudonym);
- data->next_pseudonym = NULL;
- }
if (data->next_reauth_id) {
eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
identity_len, data->next_reauth_id,
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index 9db26dc..ce3238c 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-SIM database/authenticator gateway
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -647,7 +647,8 @@
if (identity_len == 0 ||
(identity[0] != EAP_SIM_PSEUDONYM_PREFIX &&
- identity[0] != EAP_AKA_PSEUDONYM_PREFIX))
+ identity[0] != EAP_AKA_PSEUDONYM_PREFIX &&
+ identity[0] != EAP_AKA_PRIME_PSEUDONYM_PREFIX))
return NULL;
/* Remove possible realm from identity */
@@ -685,7 +686,8 @@
if (identity_len == 0 ||
(identity[0] != EAP_SIM_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PERMANENT_PREFIX))
+ identity[0] != EAP_AKA_PERMANENT_PREFIX &&
+ identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX))
return NULL;
p = data->pseudonyms;
@@ -710,7 +712,8 @@
if (identity_len == 0 ||
(identity[0] != EAP_SIM_REAUTH_ID_PREFIX &&
- identity[0] != EAP_AKA_REAUTH_ID_PREFIX))
+ identity[0] != EAP_AKA_REAUTH_ID_PREFIX &&
+ identity[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX))
return NULL;
/* Remove possible realm from identity */
@@ -777,8 +780,9 @@
* @identity_len: Length of identity in bytes
* Returns: 0 if the user is found or -1 on failure
*
- * In most cases, the user name is ['0','1'] | IMSI, i.e., 1 followed by the
- * IMSI in ASCII format, ['2','3'] | pseudonym, or ['4','5'] | reauth_id.
+ * In most cases, the user name is ['0','1','6'] | IMSI, i.e., 1 followed by
+ * the IMSI in ASCII format for EAP-SIM, ['2','3','7'] | pseudonym, or
+ * ['4','5','7'] | reauth_id.
*/
int eap_sim_db_identity_known(void *priv, const u8 *identity,
size_t identity_len)
@@ -789,21 +793,24 @@
return -1;
if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX ||
- identity[0] == EAP_AKA_PSEUDONYM_PREFIX) {
+ identity[0] == EAP_AKA_PSEUDONYM_PREFIX ||
+ identity[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) {
struct eap_sim_pseudonym *p =
eap_sim_db_get_pseudonym(data, identity, identity_len);
return p ? 0 : -1;
}
if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX ||
- identity[0] == EAP_AKA_REAUTH_ID_PREFIX) {
+ identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
+ identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) {
struct eap_sim_reauth *r =
eap_sim_db_get_reauth(data, identity, identity_len);
return r ? 0 : -1;
}
if (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PERMANENT_PREFIX) {
+ identity[0] != EAP_AKA_PERMANENT_PREFIX &&
+ identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) {
/* Unknown identity prefix */
return -1;
}
@@ -843,7 +850,7 @@
/**
* eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
* @priv: Private data pointer from eap_sim_db_init()
- * @aka: Using EAP-AKA instead of EAP-SIM
+ * @method: EAP method (SIM/AKA/AKA')
* Returns: Next pseudonym (allocated string) or %NULL on failure
*
* This function is used to generate a pseudonym for EAP-SIM. The returned
@@ -851,18 +858,31 @@
* with eap_sim_db_add_pseudonym() once the authentication has been completed
* successfully. Caller is responsible for freeing the returned buffer.
*/
-char * eap_sim_db_get_next_pseudonym(void *priv, int aka)
+char * eap_sim_db_get_next_pseudonym(void *priv, enum eap_sim_db_method method)
{
struct eap_sim_db_data *data = priv;
- return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX :
- EAP_SIM_PSEUDONYM_PREFIX);
+ char prefix = EAP_SIM_REAUTH_ID_PREFIX;
+
+ switch (method) {
+ case EAP_SIM_DB_SIM:
+ prefix = EAP_SIM_PSEUDONYM_PREFIX;
+ break;
+ case EAP_SIM_DB_AKA:
+ prefix = EAP_AKA_PSEUDONYM_PREFIX;
+ break;
+ case EAP_SIM_DB_AKA_PRIME:
+ prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
+ break;
+ }
+
+ return eap_sim_db_get_next(data, prefix);
}
/**
* eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
* @priv: Private data pointer from eap_sim_db_init()
- * @aka: Using EAP-AKA instead of EAP-SIM
+ * @method: EAP method (SIM/AKA/AKA')
* Returns: Next reauth_id (allocated string) or %NULL on failure
*
* This function is used to generate a fast re-authentication identity for
@@ -871,11 +891,24 @@
* has been completed successfully. Caller is responsible for freeing the
* returned buffer.
*/
-char * eap_sim_db_get_next_reauth_id(void *priv, int aka)
+char * eap_sim_db_get_next_reauth_id(void *priv, enum eap_sim_db_method method)
{
struct eap_sim_db_data *data = priv;
- return eap_sim_db_get_next(data, aka ? EAP_AKA_REAUTH_ID_PREFIX :
- EAP_SIM_REAUTH_ID_PREFIX);
+ char prefix = EAP_SIM_REAUTH_ID_PREFIX;
+
+ switch (method) {
+ case EAP_SIM_DB_SIM:
+ prefix = EAP_SIM_REAUTH_ID_PREFIX;
+ break;
+ case EAP_SIM_DB_AKA:
+ prefix = EAP_AKA_REAUTH_ID_PREFIX;
+ break;
+ case EAP_SIM_DB_AKA_PRIME:
+ prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
+ break;
+ }
+
+ return eap_sim_db_get_next(data, prefix);
}
@@ -1156,7 +1189,7 @@
* called once the results become available.
*
* In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in
- * ASCII format.
+ * ASCII format for EAP-AKA and '6' | IMSI for EAP-AKA'.
*
* When using an external server for AKA authentication, this function can
* always start a request and return EAP_SIM_DB_PENDING immediately if
@@ -1178,7 +1211,8 @@
char msg[40];
if (identity_len < 2 || identity == NULL ||
- identity[0] != EAP_AKA_PERMANENT_PREFIX) {
+ (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
+ identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
identity, identity_len);
return EAP_SIM_DB_FAILURE;
@@ -1281,7 +1315,8 @@
size_t i;
if (identity_len < 2 || identity == NULL ||
- identity[0] != EAP_AKA_PERMANENT_PREFIX) {
+ (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
+ identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
identity, identity_len);
return -1;
diff --git a/src/eap_server/eap_sim_db.h b/src/eap_server/eap_sim_db.h
index abe185e..1f6375a 100644
--- a/src/eap_server/eap_sim_db.h
+++ b/src/eap_server/eap_sim_db.h
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-SIM database/authenticator gateway
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2008, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -18,6 +18,15 @@
#define EAP_AKA_PERMANENT_PREFIX '0'
#define EAP_AKA_PSEUDONYM_PREFIX '2'
#define EAP_AKA_REAUTH_ID_PREFIX '4'
+#define EAP_AKA_PRIME_PERMANENT_PREFIX '6'
+#define EAP_AKA_PRIME_PSEUDONYM_PREFIX '7'
+#define EAP_AKA_PRIME_REAUTH_ID_PREFIX '8'
+
+enum eap_sim_db_method {
+ EAP_SIM_DB_SIM,
+ EAP_SIM_DB_AKA,
+ EAP_SIM_DB_AKA_PRIME
+};
void * eap_sim_db_init(const char *config,
void (*get_complete_cb)(void *ctx, void *session_ctx),
@@ -36,9 +45,11 @@
int eap_sim_db_identity_known(void *priv, const u8 *identity,
size_t identity_len);
-char * eap_sim_db_get_next_pseudonym(void *priv, int aka);
+char * eap_sim_db_get_next_pseudonym(void *priv,
+ enum eap_sim_db_method method);
-char * eap_sim_db_get_next_reauth_id(void *priv, int aka);
+char * eap_sim_db_get_next_reauth_id(void *priv,
+ enum eap_sim_db_method method);
int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
size_t identity_len, char *pseudonym);
diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/src/eapol_auth/eapol_auth_sm_i.h
index d0b7641..d7f893a 100644
--- a/src/eapol_auth/eapol_auth_sm_i.h
+++ b/src/eapol_auth/eapol_auth_sm_i.h
@@ -157,6 +157,7 @@
* Authentication server */
u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */
struct radius_class_data radius_class;
+ struct wpabuf *radius_cui; /* Chargeable-User-Identity */
/* Keys for encrypting and signing EAPOL-Key frames */
u8 *eapol_key_sign;
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index c83709f..f0cae70 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1847,6 +1847,17 @@
cert_hash, cert);
}
+
+static void eapol_sm_notify_status(void *ctx, const char *status,
+ const char *parameter)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->status_cb)
+ sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
+}
+
+
static struct eapol_callbacks eapol_cb =
{
eapol_sm_get_config,
@@ -1859,7 +1870,8 @@
eapol_sm_get_config_blob,
eapol_sm_notify_pending,
eapol_sm_eap_param_needed,
- eapol_sm_notify_cert
+ eapol_sm_notify_cert,
+ eapol_sm_notify_status
};
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 3260c61..1a20e4b 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -230,6 +230,15 @@
* cert_in_cb - Include server certificates in callback
*/
int cert_in_cb;
+
+ /**
+ * status_cb - Notification of a change in EAP status
+ * @ctx: Callback context (ctx)
+ * @status: Step in the process of EAP authentication
+ * @parameter: Step-specific parameter, e.g., EAP method name
+ */
+ void (*status_cb)(void *ctx, const char *status,
+ const char *parameter);
};
diff --git a/src/l2_packet/l2_packet_freebsd.c b/src/l2_packet/l2_packet_freebsd.c
index e24277c..2e9a04c 100644
--- a/src/l2_packet/l2_packet_freebsd.c
+++ b/src/l2_packet/l2_packet_freebsd.c
@@ -3,14 +3,8 @@
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
* Copyright (c) 2005, Sam Leffler <sam@errno.com>
*
- * 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 "includes.h"
diff --git a/src/l2_packet/l2_packet_privsep.c b/src/l2_packet/l2_packet_privsep.c
index aacd76b..6b117ca 100644
--- a/src/l2_packet/l2_packet_privsep.c
+++ b/src/l2_packet/l2_packet_privsep.c
@@ -173,7 +173,7 @@
addr.sun_family = AF_UNIX;
os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ perror("l2-pkt-privsep: bind(PF_UNIX)");
goto fail;
}
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index aeeaccb..58ada3b 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -119,7 +119,7 @@
continue;
#endif
- wpa_msg(p2p->cfg->msg_ctx, MSG_ERROR, "P2P: Expiring old peer "
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Expiring old peer "
"entry " MACSTR, MAC2STR(dev->info.p2p_device_addr));
#ifdef ANDROID_P2P
/* SD_FAIR_POLICY: Update the current sd_dev_list pointer to next device */
@@ -193,14 +193,14 @@
}
-void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr)
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr)
{
struct p2p_device *dev = NULL;
- if (!iface_addr || !p2p)
+ if (!addr || !p2p)
return;
- dev = p2p_get_device_interface(p2p, iface_addr);
+ dev = p2p_get_device(p2p, addr);
if (dev)
dev->wps_prov_info = 0;
}
@@ -315,7 +315,7 @@
p2p->pending_listen_usec = (timeout % 1000) * 1000;
if (p2p->p2p_scan_running) {
- if (p2p->start_after_scan == P2P_AFTER_SCAN_NOTHING) {
+ if (p2p->start_after_scan == P2P_AFTER_SCAN_CONNECT) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: p2p_scan running - connect is already "
"pending - skip listen");
@@ -484,13 +484,25 @@
continue; /* ignore our own entry */
dev = p2p_get_device(p2p, cli->p2p_device_addr);
if (dev) {
- /*
- * Update information only if we have not received this
- * directly from the client.
- */
if (dev->flags & (P2P_DEV_GROUP_CLIENT_ONLY |
- P2P_DEV_PROBE_REQ_ONLY))
+ P2P_DEV_PROBE_REQ_ONLY)) {
+ /*
+ * Update information since we have not
+ * received this directly from the client.
+ */
p2p_copy_client_info(dev, cli);
+ } else {
+ /*
+ * Need to update P2P Client Discoverability
+ * flag since it is valid only in P2P Group
+ * Info attribute.
+ */
+ dev->info.dev_capab &=
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+ dev->info.dev_capab |=
+ cli->dev_capab &
+ P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+ }
if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
}
@@ -573,7 +585,13 @@
}
if (msg->capability) {
- dev->info.dev_capab = msg->capability[0];
+ /*
+ * P2P Client Discoverability bit is reserved in all frames
+ * that use this function, so do not change its value here.
+ */
+ dev->info.dev_capab &= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+ dev->info.dev_capab |= msg->capability[0] &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
dev->info.group_capab = msg->capability[1];
}
@@ -582,6 +600,7 @@
dev->ext_listen_interval =
WPA_GET_LE16(msg->ext_listen_timing + 2);
}
+
if (!probe_req) {
dev->info.config_methods = msg->config_methods ?
msg->config_methods : msg->wps_config_methods;
@@ -590,7 +609,7 @@
/**
- * p2p_add_device - Add peer entries based on scan results
+ * p2p_add_device - Add peer entries based on scan results or P2P frames
* @p2p: P2P module context from p2p_init()
* @addr: Source address of Beacon or Probe Response frame (may be either
* P2P Device Address or P2P Interface Address)
@@ -598,6 +617,7 @@
* @freq: Frequency on which the Beacon or Probe Response frame was received
* @ies: IEs from the Beacon or Probe Response frame
* @ies_len: Length of ies buffer in octets
+ * @scan_res: Whether this was based on scan results
* Returns: 0 on success, -1 on failure
*
* If the scan result is for a GO, the clients in the group will also be added
@@ -606,7 +626,7 @@
* Info attributes.
*/
int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
- const u8 *ies, size_t ies_len)
+ const u8 *ies, size_t ies_len, int scan_res)
{
struct p2p_device *dev;
struct p2p_message msg;
@@ -675,16 +695,18 @@
}
}
- if (dev->listen_freq && dev->listen_freq != freq) {
+ if (dev->listen_freq && dev->listen_freq != freq && scan_res) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Update Listen frequency based on scan "
"results (" MACSTR " %d -> %d MHz (DS param %d)",
MAC2STR(dev->info.p2p_device_addr), dev->listen_freq,
freq, msg.ds_params ? *msg.ds_params : -1);
}
- dev->listen_freq = freq;
- if (msg.group_info)
- dev->oper_freq = freq;
+ if (scan_res) {
+ dev->listen_freq = freq;
+ if (msg.group_info)
+ dev->oper_freq = freq;
+ }
dev->info.level = level;
p2p_copy_wps_info(dev, 0, &msg);
@@ -703,8 +725,10 @@
break;
}
- p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq, msg.group_info,
- msg.group_info_len);
+ if (scan_res) {
+ p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq,
+ msg.group_info, msg.group_info_len);
+ }
p2p_parse_free(&msg);
@@ -821,6 +845,7 @@
{
int freq = 0;
enum p2p_scan_type type;
+ u16 pw_id = DEV_PW_DEFAULT;
if (p2p->drv_in_listen) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is still "
@@ -830,30 +855,8 @@
}
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
- if (p2p->go_neg_peer) {
- /*
- * Only scan the known listen frequency of the peer
- * during GO Negotiation start.
- */
- freq = p2p->go_neg_peer->listen_freq;
- if (freq <= 0)
- freq = p2p->go_neg_peer->oper_freq;
- type = P2P_SCAN_SPECIFIC;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
- "for freq %u (GO Neg)", freq);
- } else if (p2p->invite_peer) {
- /*
- * Only scan the known listen frequency of the peer
- * during Invite start.
- */
- freq = p2p->invite_peer->listen_freq;
- if (freq <= 0)
- freq = p2p->invite_peer->oper_freq;
- type = P2P_SCAN_SPECIFIC;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
- "for freq %u (Invite)", freq);
- } else if (p2p->find_type == P2P_FIND_PROGRESSIVE &&
- (freq = p2p_get_next_prog_freq(p2p)) > 0) {
+ if (p2p->find_type == P2P_FIND_PROGRESSIVE &&
+ (freq = p2p_get_next_prog_freq(p2p)) > 0) {
type = P2P_SCAN_SOCIAL_PLUS_ONE;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
"(+ freq %u)", freq);
@@ -864,7 +867,7 @@
if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
p2p->num_req_dev_types, p2p->req_dev_types,
- p2p->find_dev_id)) {
+ p2p->find_dev_id, pw_id)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Scan request failed");
p2p_continue_find(p2p);
@@ -1016,12 +1019,14 @@
case P2P_FIND_PROGRESSIVE:
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
p2p->num_req_dev_types,
- p2p->req_dev_types, dev_id);
+ p2p->req_dev_types, dev_id,
+ DEV_PW_DEFAULT);
break;
case P2P_FIND_ONLY_SOCIAL:
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0,
p2p->num_req_dev_types,
- p2p->req_dev_types, dev_id);
+ p2p->req_dev_types, dev_id,
+ DEV_PW_DEFAULT);
break;
default:
return -1;
@@ -1090,11 +1095,21 @@
p2p->go_neg_peer = NULL;
p2p->sd_peer = NULL;
p2p->invite_peer = NULL;
+ p2p_stop_listen_for_freq(p2p, freq);
+}
+
+
+void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
+{
if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip stop_listen "
"since we are on correct channel for response");
return;
}
+ if (p2p->in_listen) {
+ p2p->in_listen = 0;
+ p2p_clear_timeout(p2p);
+ }
if (p2p->drv_in_listen) {
/*
* The driver may not deliver callback to p2p_listen_end()
@@ -1217,21 +1232,22 @@
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
- unsigned int force_freq, int persistent_group)
+ unsigned int force_freq, int persistent_group,
+ const u8 *force_ssid, size_t force_ssid_len,
+ int pd_before_go_neg)
{
struct p2p_device *dev;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Request to start group negotiation - peer=" MACSTR
" GO Intent=%d Intended Interface Address=" MACSTR
- " wps_method=%d persistent_group=%d",
+ " wps_method=%d persistent_group=%d pd_before_go_neg=%d",
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
- wps_method, persistent_group);
+ wps_method, persistent_group, pd_before_go_neg);
if (p2p_prepare_channel(p2p, force_freq) < 0)
return -1;
- p2p->ssid_set = 0;
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1264,10 +1280,23 @@
*/
}
+ p2p->ssid_set = 0;
+ if (force_ssid) {
+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
+ force_ssid, force_ssid_len);
+ os_memcpy(p2p->ssid, force_ssid, force_ssid_len);
+ p2p->ssid_len = force_ssid_len;
+ p2p->ssid_set = 1;
+ }
+
dev->flags &= ~P2P_DEV_NOT_YET_READY;
dev->flags &= ~P2P_DEV_USER_REJECTED;
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
+ if (pd_before_go_neg)
+ dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG;
+ else
+ dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
dev->connect_reqs = 0;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
@@ -1315,7 +1344,8 @@
int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
- unsigned int force_freq, int persistent_group)
+ unsigned int force_freq, int persistent_group,
+ const u8 *force_ssid, size_t force_ssid_len)
{
struct p2p_device *dev;
@@ -1337,6 +1367,15 @@
return -1;
}
+ p2p->ssid_set = 0;
+ if (force_ssid) {
+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
+ force_ssid, force_ssid_len);
+ os_memcpy(p2p->ssid, force_ssid, force_ssid_len);
+ p2p->ssid_len = force_ssid_len;
+ p2p->ssid_set = 1;
+ }
+
dev->flags &= ~P2P_DEV_NOT_YET_READY;
dev->flags &= ~P2P_DEV_USER_REJECTED;
dev->go_neg_req_sent = 0;
@@ -1821,16 +1860,23 @@
{
struct wpabuf *buf;
u8 *len;
+ int pw_id = -1;
buf = wpabuf_alloc(1000);
if (buf == NULL)
return NULL;
- p2p_build_wps_ie(p2p, buf, DEV_PW_DEFAULT, 1);
+ if (p2p->go_neg_peer) {
+ /* Advertise immediate availability of WPS credential */
+ pw_id = p2p_wps_method_pw_id(p2p->go_neg_peer->wps_method);
+ }
+
+ p2p_build_wps_ie(p2p, buf, pw_id, 1);
/* P2P IE */
len = p2p_buf_add_ie_hdr(buf);
- p2p_buf_add_capability(buf, p2p->dev_capab, 0);
+ p2p_buf_add_capability(buf, p2p->dev_capab &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
if (p2p->ext_listen_interval)
p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
p2p->ext_listen_interval);
@@ -1874,9 +1920,9 @@
}
-static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
- const u8 *dst, const u8 *bssid, const u8 *ie,
- size_t ie_len)
+static enum p2p_probe_req_status
+p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+ const u8 *bssid, const u8 *ie, size_t ie_len)
{
struct ieee802_11_elems elems;
struct wpabuf *buf;
@@ -1886,55 +1932,55 @@
if (!p2p->in_listen || !p2p->drv_in_listen) {
/* not in Listen state - ignore Probe Request */
- return;
+ return P2P_PREQ_NOT_LISTEN;
}
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
ParseFailed) {
/* Ignore invalid Probe Request frames */
- return;
+ return P2P_PREQ_MALFORMED;
}
if (elems.p2p == NULL) {
/* not a P2P probe - ignore it */
- return;
+ return P2P_PREQ_NOT_P2P;
}
if (dst && !is_broadcast_ether_addr(dst) &&
os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
/* Not sent to the broadcast address or our P2P Device Address
*/
- return;
+ return P2P_PREQ_NOT_PROCESSED;
}
if (bssid && !is_broadcast_ether_addr(bssid)) {
/* Not sent to the Wildcard BSSID */
- return;
+ return P2P_PREQ_NOT_PROCESSED;
}
if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN ||
os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
0) {
/* not using P2P Wildcard SSID - ignore */
- return;
+ return P2P_PREQ_NOT_PROCESSED;
}
if (supp_rates_11b_only(&elems)) {
/* Indicates support for 11b rates only */
- return;
+ return P2P_PREQ_NOT_P2P;
}
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
/* Could not parse P2P attributes */
- return;
+ return P2P_PREQ_NOT_P2P;
}
if (msg.device_id &&
- os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN != 0)) {
+ os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
/* Device ID did not match */
p2p_parse_free(&msg);
- return;
+ return P2P_PREQ_NOT_PROCESSED;
}
/* Check Requested Device Type match */
@@ -1942,12 +1988,14 @@
!p2p_match_dev_type(p2p, msg.wps_attributes)) {
/* No match with Requested Device Type */
p2p_parse_free(&msg);
- return;
+ return P2P_PREQ_NOT_PROCESSED;
}
p2p_parse_free(&msg);
- if (!p2p->cfg->send_probe_resp)
- return; /* Response generated elsewhere */
+ if (!p2p->cfg->send_probe_resp) {
+ /* Response generated elsewhere */
+ return P2P_PREQ_NOT_PROCESSED;
+ }
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Reply to P2P Probe Request in Listen state");
@@ -1960,12 +2008,12 @@
*/
ies = p2p_build_probe_resp_ies(p2p);
if (ies == NULL)
- return;
+ return P2P_PREQ_NOT_PROCESSED;
buf = wpabuf_alloc(200 + wpabuf_len(ies));
if (buf == NULL) {
wpabuf_free(ies);
- return;
+ return P2P_PREQ_NOT_PROCESSED;
}
resp = NULL;
@@ -2008,15 +2056,20 @@
p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf);
wpabuf_free(buf);
+
+ return P2P_PREQ_NOT_PROCESSED;
}
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
- const u8 *bssid, const u8 *ie, size_t ie_len)
+enum p2p_probe_req_status
+p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+ const u8 *bssid, const u8 *ie, size_t ie_len)
{
+ enum p2p_probe_req_status res;
+
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
- p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
+ res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
p2p->go_neg_peer &&
@@ -2027,7 +2080,7 @@
"P2P: Found GO Negotiation peer - try to start GO "
"negotiation from timeout");
eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
- return 1;
+ return P2P_PREQ_PROCESSED;
}
if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
@@ -2039,10 +2092,10 @@
"P2P: Found Invite peer - try to start Invite from "
"timeout");
eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
- return 1;
+ return P2P_PREQ_PROCESSED;
}
- return 0;
+ return res;
}
@@ -2156,29 +2209,37 @@
}
+int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr)
+{
+ struct p2p_message msg;
+
+ os_memset(&msg, 0, sizeof(msg));
+ if (p2p_parse_p2p_ie(p2p_ie, &msg))
+ return -1;
+
+ if (msg.p2p_device_addr) {
+ os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN);
+ return 0;
+ } else if (msg.device_id) {
+ os_memcpy(dev_addr, msg.device_id, ETH_ALEN);
+ return 0;
+ }
+ return -1;
+}
+
+
int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr)
{
struct wpabuf *p2p_ie;
- struct p2p_message msg;
+ int ret;
p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
P2P_IE_VENDOR_TYPE);
if (p2p_ie == NULL)
return -1;
- os_memset(&msg, 0, sizeof(msg));
- if (p2p_parse_p2p_ie(p2p_ie, &msg)) {
- wpabuf_free(p2p_ie);
- return -1;
- }
-
- if (msg.p2p_device_addr == NULL) {
- wpabuf_free(p2p_ie);
- return -1;
- }
-
- os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN);
+ ret = p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr);
wpabuf_free(p2p_ie);
- return 0;
+ return ret;
}
@@ -2256,6 +2317,17 @@
p2p->cfg->model_number = os_strdup(cfg->model_number);
if (cfg->serial_number)
p2p->cfg->serial_number = os_strdup(cfg->serial_number);
+ if (cfg->pref_chan) {
+ p2p->cfg->pref_chan = os_malloc(cfg->num_pref_chan *
+ sizeof(struct p2p_channel));
+ if (p2p->cfg->pref_chan) {
+ os_memcpy(p2p->cfg->pref_chan, cfg->pref_chan,
+ cfg->num_pref_chan *
+ sizeof(struct p2p_channel));
+ } else
+ p2p->cfg->num_pref_chan = 0;
+ }
+
#ifdef ANDROID_P2P
/* 100ms listen time is too less to receive the response frames in some scenarios
* increasing min listen time to 200ms.
@@ -2298,6 +2370,7 @@
os_free(p2p->cfg->model_name);
os_free(p2p->cfg->model_number);
os_free(p2p->cfg->serial_number);
+ os_free(p2p->cfg->pref_chan);
os_free(p2p->groups);
wpabuf_free(p2p->sd_resp);
os_free(p2p->after_scan_tx);
@@ -2309,16 +2382,7 @@
void p2p_flush(struct p2p_data *p2p)
{
struct p2p_device *dev, *prev;
- p2p_clear_timeout(p2p);
-#ifdef ANDROID_P2P
- if (p2p->state == P2P_SEARCH)
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
- P2P_EVENT_FIND_STOPPED);
-#endif
- p2p_set_state(p2p, P2P_IDLE);
- p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
- p2p->go_neg_peer = NULL;
- eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+ p2p_stop_find(p2p);
dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device,
list) {
dl_list_del(&dev->list);
@@ -2671,17 +2735,7 @@
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
int level, const u8 *ies, size_t ies_len)
{
- p2p_add_device(p2p, bssid, freq, level, ies, ies_len);
-
- if (p2p->go_neg_peer && p2p->state == P2P_SEARCH &&
- os_memcmp(p2p->go_neg_peer->info.p2p_device_addr, bssid, ETH_ALEN)
- == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Found GO Negotiation peer - try to start GO "
- "negotiation");
- p2p_connect_send(p2p, p2p->go_neg_peer);
- return 1;
- }
+ p2p_add_device(p2p, bssid, freq, level, ies, ies_len, 1);
return 0;
}
@@ -2706,7 +2760,8 @@
void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
{
u8 *len = p2p_buf_add_ie_hdr(ies);
- p2p_buf_add_capability(ies, p2p->dev_capab, 0);
+ p2p_buf_add_capability(ies, p2p->dev_capab &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
if (dev_id)
p2p_buf_add_device_id(ies, dev_id);
if (p2p->cfg->reg_class && p2p->cfg->channel)
@@ -2748,19 +2803,14 @@
}
if (success) {
-#ifndef ANDROID_P2P
- dev->go_neg_req_sent++;
-#endif
if (dev->flags & P2P_DEV_USER_REJECTED) {
p2p_set_state(p2p, P2P_IDLE);
return;
}
- }
-#ifdef ANDROID_P2P
- else {
+ } else if (dev->go_neg_req_sent) {
+ /* Cancel the increment from p2p_connect_send() on failure */
dev->go_neg_req_sent--;
}
-#endif
if (!success &&
(dev->info.dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY) &&
@@ -2978,6 +3028,18 @@
"new one");
return 1;
}
+ if (p2p->pending_listen_freq) {
+ /*
+ * Better wait a bit if the driver is unable to start
+ * offchannel operation for some reason. p2p_search()
+ * will be started from internal timeout.
+ */
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Listen "
+ "operation did not seem to start - delay "
+ "search phase to avoid busy loop");
+ p2p_set_timeout(p2p, 0, 100000);
+ return 1;
+ }
p2p_search(p2p);
return 1;
}
@@ -2989,6 +3051,14 @@
static void p2p_timeout_connect(struct p2p_data *p2p)
{
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ if (p2p->go_neg_peer &&
+ (p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Wait for GO "
+ "Negotiation Confirm timed out - assume GO "
+ "Negotiation failed");
+ p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ return;
+ }
p2p_set_state(p2p, P2P_CONNECT_LISTEN);
p2p_listen_in_find(p2p);
}
@@ -3802,6 +3872,28 @@
}
+int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
+ const struct p2p_channel *pref_chan)
+{
+ struct p2p_channel *n;
+
+ if (pref_chan) {
+ n = os_malloc(num_pref_chan * sizeof(struct p2p_channel));
+ if (n == NULL)
+ return -1;
+ os_memcpy(n, pref_chan,
+ num_pref_chan * sizeof(struct p2p_channel));
+ } else
+ n = NULL;
+
+ os_free(p2p->cfg->pref_chan);
+ p2p->cfg->pref_chan = n;
+ p2p->cfg->num_pref_chan = num_pref_chan;
+
+ return 0;
+}
+
+
int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
u8 *iface_addr)
{
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index fe98f5e..7006707 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -131,7 +131,6 @@
enum p2p_scan_type {
P2P_SCAN_SOCIAL,
P2P_SCAN_FULL,
- P2P_SCAN_SPECIFIC,
P2P_SCAN_SOCIAL_PLUS_ONE
};
@@ -218,6 +217,11 @@
P2P_PROV_DISC_REJECTED,
};
+struct p2p_channel {
+ u8 op_class;
+ u8 chan;
+};
+
/**
* struct p2p_config - P2P configuration
*
@@ -265,6 +269,16 @@
struct p2p_channels channels;
/**
+ * num_pref_chan - Number of pref_chan entries
+ */
+ unsigned int num_pref_chan;
+
+ /**
+ * pref_chan - Preferred channels for GO Negotiation
+ */
+ struct p2p_channel *pref_chan;
+
+ /**
* pri_dev_type - Primary Device Type (see WPS)
*/
u8 pri_dev_type[8];
@@ -354,14 +368,14 @@
* @num_req_dev_types: Number of requested device types
* @req_dev_types: Array containing requested device types
* @dev_id: Device ID to search for or %NULL to find all devices
+ * @pw_id: Device Password ID
* Returns: 0 on success, -1 on failure
*
* This callback function is used to request a P2P scan or search
* operation to be completed. Type type argument specifies which type
* of scan is to be done. @P2P_SCAN_SOCIAL indicates that only the
* social channels (1, 6, 11) should be scanned. @P2P_SCAN_FULL
- * indicates that all channels are to be scanned. @P2P_SCAN_SPECIFIC
- * request a scan of a single channel specified by freq.
+ * indicates that all channels are to be scanned.
* @P2P_SCAN_SOCIAL_PLUS_ONE request scan of all the social channels
* plus one extra channel specified by freq.
*
@@ -377,7 +391,7 @@
*/
int (*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);
+ const u8 *req_dev_types, const u8 *dev_id, u16 pw_id);
/**
* send_probe_resp - Transmit a Probe Response frame
@@ -861,12 +875,20 @@
* @persistent_group: Whether to create a persistent group (0 = no, 1 =
* persistent group without persistent reconnect, 2 = persistent group with
* persistent reconnect)
+ * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate
+ * a new SSID
+ * @force_ssid_len: Length of $force_ssid buffer
+ * @pd_before_go_neg: Whether to send Provision Discovery prior to GO
+ * Negotiation as an interoperability workaround when initiating group
+ * formation
* Returns: 0 on success, -1 on failure
*/
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
- unsigned int force_freq, int persistent_group);
+ unsigned int force_freq, int persistent_group,
+ const u8 *force_ssid, size_t force_ssid_len,
+ int pd_before_go_neg);
/**
* p2p_authorize - Authorize P2P group formation (GO negotiation)
@@ -879,6 +901,9 @@
* @persistent_group: Whether to create a persistent group (0 = no, 1 =
* persistent group without persistent reconnect, 2 = persistent group with
* persistent reconnect)
+ * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate
+ * a new SSID
+ * @force_ssid_len: Length of $force_ssid buffer
* Returns: 0 on success, -1 on failure
*
* This is like p2p_connect(), but the actual group negotiation is not
@@ -887,7 +912,8 @@
int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
- unsigned int force_freq, int persistent_group);
+ unsigned int force_freq, int persistent_group,
+ const u8 *force_ssid, size_t force_ssid_len);
/**
* p2p_reject - Reject peer device (explicitly block connection attempts)
@@ -1060,17 +1086,34 @@
/**
* p2p_clear_provisioning_info - Clear any stored provisioning info
* @p2p: P2P module context from p2p_init()
- * @iface_addr: Peer P2P Interface Address
+ * @iface_addr: Peer P2P Device Address
*
* This function is used to clear stored WPS provisioning info for the given
* peer.
*/
-void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr);
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr);
/* Event notifications from lower layer driver operations */
/**
+ * enum p2p_probe_req_status
+ *
+ * @P2P_PREQ_MALFORMED: frame was not well-formed
+ * @P2P_PREQ_NOT_LISTEN: device isn't in listen state, frame ignored
+ * @P2P_PREQ_NOT_P2P: frame was not a P2P probe request
+ * @P2P_PREQ_P2P_NOT_PROCESSED: frame was P2P but wasn't processed
+ * @P2P_PREQ_P2P_PROCESSED: frame has been processed by P2P
+ */
+enum p2p_probe_req_status {
+ P2P_PREQ_MALFORMED,
+ P2P_PREQ_NOT_LISTEN,
+ P2P_PREQ_NOT_P2P,
+ P2P_PREQ_NOT_PROCESSED,
+ P2P_PREQ_PROCESSED
+};
+
+/**
* p2p_probe_req_rx - Report reception of a Probe Request frame
* @p2p: P2P module context from p2p_init()
* @addr: Source MAC address
@@ -1078,10 +1121,11 @@
* @bssid: BSSID if available or %NULL
* @ie: Information elements from the Probe Request frame body
* @ie_len: Length of ie buffer in octets
- * Returns: 0 to indicate the frame was not processed or 1 if it was
+ * Returns: value indicating the type and status of the probe request
*/
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
- const u8 *bssid, const u8 *ie, size_t ie_len);
+enum p2p_probe_req_status
+p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+ const u8 *bssid, const u8 *ie, size_t ie_len);
/**
* p2p_rx_action - Report received Action frame
@@ -1220,6 +1264,16 @@
unsigned int max_clients;
/**
+ * ssid - Group SSID
+ */
+ u8 ssid[32];
+
+ /**
+ * ssid_len - Length of SSID
+ */
+ size_t ssid_len;
+
+ /**
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
@@ -1371,6 +1425,15 @@
int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end);
/**
+ * p2p_parse_dev_addr_in_p2p_ie - Parse P2P Device Address from a concatenated
+ * P2P IE
+ * @p2p_ie: P2P IE
+ * @dev_addr: Buffer for returning P2P Device Address
+ * Returns: 0 on success or -1 if P2P Device Address could not be parsed
+ */
+int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr);
+
+/**
* p2p_parse_dev_addr - Parse P2P Device Address from P2P IE(s)
* @ies: Information elements from scan results
* @ies_len: ies buffer length in octets
@@ -1608,6 +1671,16 @@
int cfg_op_channel);
/**
+ * p2p_set_pref_chan - Set P2P preferred channel list
+ * @p2p: P2P module context from p2p_init()
+ * @num_pref_chan: Number of entries in pref_chan list
+ * @pref_chan: Preferred channels or %NULL to remove preferences
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
+ const struct p2p_channel *pref_chan);
+
+/**
* p2p_in_progress - Check whether a P2P operation is progress
* @p2p: P2P module context from p2p_init()
* Returns: 0 if P2P module is idle or 1 if an operation is in progress
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 2106964..def422d 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -351,7 +351,7 @@
}
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, u16 pw_id,
+void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
int all_attr)
{
u8 *len;
@@ -369,11 +369,14 @@
wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
}
- /* Device Password ID */
- wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
- wpabuf_put_be16(buf, 2);
- wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d", pw_id);
- wpabuf_put_be16(buf, pw_id);
+ if (pw_id >= 0) {
+ /* Device Password ID */
+ wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
+ wpabuf_put_be16(buf, 2);
+ wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d",
+ pw_id);
+ wpabuf_put_be16(buf, pw_id);
+ }
if (all_attr) {
wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 6e818c2..248b2a0 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -98,7 +98,7 @@
}
-static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
+u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
{
switch (wps_method) {
case WPS_PIN_DISPLAY:
@@ -155,7 +155,9 @@
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
- p2p_buf_add_capability(buf, p2p->dev_capab, group_capab);
+ p2p_buf_add_capability(buf, p2p->dev_capab &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+ group_capab);
p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) |
p2p->next_tie_breaker);
p2p->next_tie_breaker = !p2p->next_tie_breaker;
@@ -184,6 +186,23 @@
struct wpabuf *req;
int freq;
+ if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
+ u16 config_method;
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Use PD-before-GO-Neg workaround for " MACSTR,
+ MAC2STR(dev->info.p2p_device_addr));
+ if (dev->wps_method == WPS_PIN_DISPLAY)
+ config_method = WPS_CONFIG_KEYPAD;
+ else if (dev->wps_method == WPS_PIN_KEYPAD)
+ config_method = WPS_CONFIG_DISPLAY;
+ else if (dev->wps_method == WPS_PBC)
+ config_method = WPS_CONFIG_PUSHBUTTON;
+ else
+ return -1;
+ return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
+ config_method, 0, 0);
+ }
+
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
if (freq <= 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -203,9 +222,6 @@
p2p->go_neg_peer = dev;
dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
dev->connect_reqs++;
-#ifdef ANDROID_P2P
- dev->go_neg_req_sent++;
-#endif
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
wpabuf_head(req), wpabuf_len(req), 200) < 0) {
@@ -213,7 +229,8 @@
"P2P: Failed to send Action frame");
/* Use P2P find to recover and retry */
p2p_set_timeout(p2p, 0, 0);
- }
+ } else
+ dev->go_neg_req_sent++;
wpabuf_free(req);
@@ -253,7 +270,9 @@
if (p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
}
- p2p_buf_add_capability(buf, p2p->dev_capab, group_capab);
+ p2p_buf_add_capability(buf, p2p->dev_capab &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+ group_capab);
p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
p2p_buf_add_config_timeout(buf, 100, 20);
if (peer && peer->go_state == REMOTE_GO) {
@@ -299,6 +318,7 @@
struct p2p_reg_class *cl;
int freq;
u8 op_reg_class, op_channel;
+ unsigned int i;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
"channel (reg_class %u channel %u) not acceptable to the "
@@ -331,6 +351,21 @@
return;
}
+ /* Select channel with highest preference if the peer supports it */
+ for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
+ if (p2p_channels_includes(intersection,
+ p2p->cfg->pref_chan[i].op_class,
+ p2p->cfg->pref_chan[i].chan)) {
+ p2p->op_reg_class = p2p->cfg->pref_chan[i].op_class;
+ p2p->op_channel = p2p->cfg->pref_chan[i].chan;
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick "
+ "highest preferred chnnel (op_class %u "
+ "channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
+ }
+ }
+
/*
* Fall back to whatever is included in the channel intersection since
* no better options seems to be available.
@@ -641,6 +676,17 @@
if (status == P2P_SC_SUCCESS) {
p2p->pending_action_state = P2P_PENDING_GO_NEG_RESPONSE;
dev->flags |= P2P_DEV_WAIT_GO_NEG_CONFIRM;
+ if (os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) < 0) {
+ /*
+ * Peer has smaller address, so the GO Negotiation
+ * Response from us is expected to complete
+ * negotiation. Ignore a GO Negotiation Response from
+ * the peer if it happens to be received after this
+ * point due to a race condition in GO Negotiation
+ * Request transmission and processing.
+ */
+ dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
+ }
} else
p2p->pending_action_state =
P2P_PENDING_GO_NEG_RESPONSE_FAILURE;
@@ -688,7 +734,9 @@
if (p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
}
- p2p_buf_add_capability(buf, p2p->dev_capab, group_capab);
+ p2p_buf_add_capability(buf, p2p->dev_capab &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+ group_capab);
if (go || resp_chan == NULL)
p2p_buf_add_operating_channel(buf, p2p->cfg->country,
p2p->op_reg_class,
@@ -992,7 +1040,7 @@
else
freq = dev->listen_freq;
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
- wpabuf_head(conf), wpabuf_len(conf), 200) < 0) {
+ wpabuf_head(conf), wpabuf_len(conf), 0) < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Failed to send Action frame");
p2p_go_neg_failed(p2p, dev, -1);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index fafd135..8d4a3cb 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -135,11 +135,10 @@
static void p2p_group_add_common_ies(struct p2p_group *group,
struct wpabuf *ie)
{
- u8 dev_capab = 0, group_capab = 0;
+ u8 dev_capab = group->p2p->dev_capab, group_capab = 0;
/* P2P Capability */
- dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
- dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;
+ dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
if (group->cfg->persistent_group) {
group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
@@ -731,3 +730,15 @@
return 0;
}
+
+
+int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
+ size_t group_id_len)
+{
+ if (group_id_len != ETH_ALEN + group->cfg->ssid_len)
+ return 0;
+ if (os_memcmp(group_id, group->p2p->cfg->dev_addr, ETH_ALEN) != 0)
+ return 0;
+ return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid,
+ group->cfg->ssid_len) == 0;
+}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 4ccd38d..5e21249 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -90,6 +90,7 @@
#define P2P_DEV_PD_FOR_JOIN BIT(14)
#define P2P_DEV_REPORTED_ONCE BIT(15)
#define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
+#define P2P_DEV_PD_BEFORE_GO_NEG BIT(17)
unsigned int flags;
int status; /* enum p2p_status_code */
@@ -557,6 +558,8 @@
u8 p2p_group_presence_req(struct p2p_group *group,
const u8 *client_interface_addr,
const u8 *noa, size_t noa_len);
+int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
+ size_t group_id_len);
void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
@@ -588,7 +591,7 @@
void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
u16 interval);
void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p);
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, u16 pw_id,
+void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
int all_attr);
/* p2p_sd.c */
@@ -616,6 +619,7 @@
void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len);
int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev);
+u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method);
/* p2p_pd.c */
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
@@ -660,7 +664,7 @@
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, int level,
- const u8 *ies, size_t ies_len);
+ 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,
const u8 *addr);
@@ -675,5 +679,6 @@
int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
size_t len, unsigned int wait_time);
+void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
#endif /* P2P_I_H */
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 417f1e7..5925549 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -121,7 +121,8 @@
"P2P: Invitation Request from unknown peer "
MACSTR, MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) {
+ if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
+ {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Invitation Request add device failed "
MACSTR, MAC2STR(sa));
@@ -344,6 +345,8 @@
req = p2p_build_invitation_req(p2p, dev, go_dev_addr);
if (req == NULL)
return -1;
+ if (p2p->state != P2P_IDLE)
+ p2p_stop_listen_for_freq(p2p, freq);
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Sending Invitation Request");
p2p_set_state(p2p, P2P_INVITE);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 55a3b90..38a9dd8 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -54,7 +54,8 @@
p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
len = p2p_buf_add_ie_hdr(buf);
- p2p_buf_add_capability(buf, p2p->dev_capab, 0);
+ p2p_buf_add_capability(buf, p2p->dev_capab &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
p2p_buf_add_device_info(buf, p2p, NULL);
if (go) {
p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
@@ -110,7 +111,8 @@
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Provision Discovery Request from "
"unknown peer " MACSTR, MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) {
+ if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
+ {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Provision Discovery Request add device "
"failed " MACSTR, MAC2STR(sa));
@@ -125,6 +127,21 @@
goto out;
}
+ if (msg.group_id) {
+ size_t i;
+ for (i = 0; i < p2p->num_groups; i++) {
+ if (p2p_group_is_group_id_match(p2p->groups[i],
+ msg.group_id,
+ msg.group_id_len))
+ break;
+ }
+ if (i == p2p->num_groups) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: PD "
+ "request for unknown P2P Group ID - reject");
+ goto out;
+ }
+ }
+
if (dev)
dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
P2P_DEV_PD_PEER_KEYPAD);
@@ -198,6 +215,7 @@
struct p2p_message msg;
struct p2p_device *dev;
u16 report_config_methods = 0;
+ int success = 0;
if (p2p_parse(data, len, &msg))
return;
@@ -266,11 +284,21 @@
dev->wps_prov_info = msg.wps_config_methods;
p2p_parse_free(&msg);
+ success = 1;
out:
dev->req_config_methods = 0;
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
- if (p2p->cfg->prov_disc_resp)
+ if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Start GO Neg after the PD-before-GO-Neg "
+ "workaround with " MACSTR,
+ MAC2STR(dev->info.p2p_device_addr));
+ dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
+ p2p_connect_send(p2p, dev);
+ return;
+ }
+ if (success && p2p->cfg->prov_disc_resp)
p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
report_config_methods);
}
@@ -316,6 +344,8 @@
if (req == NULL)
return -1;
+ if (p2p->state != P2P_IDLE)
+ p2p_stop_listen_for_freq(p2p, freq);
p2p->pending_action_state = P2P_PENDING_PD;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 37b3f7b..0509767 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -364,9 +364,14 @@
"previous SD response");
wpabuf_free(p2p->sd_resp);
}
+ p2p->sd_resp = wpabuf_dup(resp_tlvs);
+ if (p2p->sd_resp == NULL) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_ERROR, "P2P: Failed to "
+ "allocate SD response fragmentation area");
+ return;
+ }
os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN);
p2p->sd_resp_dialog_token = dialog_token;
- p2p->sd_resp = wpabuf_dup(resp_tlvs);
p2p->sd_resp_pos = 0;
p2p->sd_frag_id = 0;
resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS,
@@ -404,9 +409,18 @@
u16 slen;
u16 update_indic;
+#ifdef ANDROID_P2P
+ if (p2p->state != P2P_SD_DURING_FIND) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: #### Not ignoring unexpected GAS Initial Response from "
+ MACSTR " state %d", MAC2STR(sa), p2p->state);
+ }
+ if (p2p->sd_peer == NULL ||
+#else
if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
+#endif
os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_ERROR,
+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
"P2P: Ignore unexpected GAS Initial Response from "
MACSTR, MAC2STR(sa));
return;
@@ -645,9 +659,18 @@
wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len);
- if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
- os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
+#ifdef ANDROID_P2P
+ if (p2p->state != P2P_SD_DURING_FIND) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: #### Not ignoring unexpected GAS Comeback Response from "
+ MACSTR " state %d", MAC2STR(sa), p2p->state);
+ }
+ if (p2p->sd_peer == NULL ||
+#else
+ if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
+#endif
+ os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
"P2P: Ignore unexpected GAS Comeback Response from "
MACSTR, MAC2STR(sa));
return;
@@ -842,7 +865,7 @@
{
struct p2p_sd_query *q;
#ifdef ANDROID_P2P
- /* Currently, supplicant doesn't support more than one pending broadcast SD request.
+ /* Currently, supplicant doesn't support more than one pending broadcast SD request.
* So reject if application is registering another one before cancelling the existing one.
*/
for (q = p2p->sd_queries; q; q = q->next) {
@@ -872,7 +895,7 @@
q->next = p2p->sd_queries;
p2p->sd_queries = q;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Added SD Query %p for_all_peers %d", q, q->for_all_peers);
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Added SD Query %p", q);
if (dst == NULL) {
struct p2p_device *dev;
@@ -893,24 +916,10 @@
int p2p_sd_cancel_request(struct p2p_data *p2p, void *req)
{
if (p2p_unlink_sd_query(p2p, req)) {
-#ifdef ANDROID_P2P
- struct p2p_device *dev;
- struct p2p_sd_query *q = (struct p2p_sd_query *)req;
-#endif
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Cancel pending SD query %p", req);
#ifdef ANDROID_P2P
- /* If the request is a bcast query, then clear the
- * P2P_DEV_SD_INFO flag so that when new sd query is registered,
- * we will send the SD request frames to peer devices.
- */
- if(q->for_all_peers) {
- p2p->sd_dev_list = NULL;
- dl_list_for_each(dev, &p2p->devices,
- struct p2p_device, list) {
- dev->flags &= ~P2P_DEV_SD_INFO;
- }
- }
+ p2p->sd_dev_list = NULL;
#endif
p2p_free_sd_query(req);
return 0;
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 0dd6b12..2b9cbca 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -147,6 +147,12 @@
case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
case RADIUS_CODE_RESERVED: return "Reserved";
+ case RADIUS_CODE_DISCONNECT_REQUEST: return "Disconnect-Request";
+ case RADIUS_CODE_DISCONNECT_ACK: return "Disconnect-ACK";
+ case RADIUS_CODE_DISCONNECT_NAK: return "Disconnect-NAK";
+ case RADIUS_CODE_COA_REQUEST: return "CoA-Request";
+ case RADIUS_CODE_COA_ACK: return "CoA-ACK";
+ case RADIUS_CODE_COA_NAK: return "CoA-NAK";
default: return "?Unknown?";
}
}
@@ -222,9 +228,10 @@
RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity",
+ { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity",
RADIUS_ATTR_TEXT },
{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
+ { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }
};
#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
@@ -406,6 +413,45 @@
}
+int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len,
+ const struct radius_hdr *req_hdr)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ u8 auth[MD5_MAC_LEN];
+ struct radius_attr_hdr *attr;
+
+ os_memset(auth, 0, MD5_MAC_LEN);
+ attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+ auth, MD5_MAC_LEN);
+ if (attr == NULL) {
+ wpa_printf(MSG_WARNING, "Could not add Message-Authenticator");
+ return -1;
+ }
+
+ msg->hdr->length = htons(wpabuf_len(msg->buf));
+ os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
+ hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+ wpabuf_len(msg->buf), (u8 *) (attr + 1));
+
+ /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
+ addr[0] = wpabuf_head_u8(msg->buf);
+ len[0] = wpabuf_len(msg->buf);
+ addr[1] = secret;
+ len[1] = secret_len;
+ if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0)
+ return -1;
+
+ if (wpabuf_len(msg->buf) > 0xffff) {
+ wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
+ (unsigned long) wpabuf_len(msg->buf));
+ return -1;
+ }
+ return 0;
+}
+
+
void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
size_t secret_len)
{
@@ -427,6 +473,88 @@
}
+int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len)
+{
+ const u8 *addr[4];
+ size_t len[4];
+ u8 zero[MD5_MAC_LEN];
+ u8 hash[MD5_MAC_LEN];
+
+ os_memset(zero, 0, sizeof(zero));
+ addr[0] = (u8 *) msg->hdr;
+ len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
+ addr[1] = zero;
+ len[1] = MD5_MAC_LEN;
+ addr[2] = (u8 *) (msg->hdr + 1);
+ len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
+ addr[3] = secret;
+ len[3] = secret_len;
+ md5_vector(4, addr, len, hash);
+ return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
+}
+
+
+int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len)
+{
+ const u8 *addr[4];
+ size_t len[4];
+ u8 zero[MD5_MAC_LEN];
+ u8 hash[MD5_MAC_LEN];
+ u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
+ u8 orig_authenticator[16];
+
+ struct radius_attr_hdr *attr = NULL, *tmp;
+ size_t i;
+
+ os_memset(zero, 0, sizeof(zero));
+ addr[0] = (u8 *) msg->hdr;
+ len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
+ addr[1] = zero;
+ len[1] = MD5_MAC_LEN;
+ addr[2] = (u8 *) (msg->hdr + 1);
+ len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
+ addr[3] = secret;
+ len[3] = secret_len;
+ md5_vector(4, addr, len, hash);
+ if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
+ return 1;
+
+ for (i = 0; i < msg->attr_used; i++) {
+ tmp = radius_get_attr_hdr(msg, i);
+ if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
+ if (attr != NULL) {
+ wpa_printf(MSG_WARNING, "Multiple "
+ "Message-Authenticator attributes "
+ "in RADIUS message");
+ return 1;
+ }
+ attr = tmp;
+ }
+ }
+
+ if (attr == NULL) {
+ /* Message-Authenticator is MAY; not required */
+ return 0;
+ }
+
+ os_memcpy(orig, attr + 1, MD5_MAC_LEN);
+ os_memset(attr + 1, 0, MD5_MAC_LEN);
+ os_memcpy(orig_authenticator, msg->hdr->authenticator,
+ sizeof(orig_authenticator));
+ os_memset(msg->hdr->authenticator, 0,
+ sizeof(msg->hdr->authenticator));
+ hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+ wpabuf_len(msg->buf), auth);
+ os_memcpy(attr + 1, orig, MD5_MAC_LEN);
+ os_memcpy(msg->hdr->authenticator, orig_authenticator,
+ sizeof(orig_authenticator));
+
+ return os_memcmp(orig, auth, MD5_MAC_LEN) != 0;
+}
+
+
static int radius_msg_add_attr_to_array(struct radius_msg *msg,
struct radius_attr_hdr *attr)
{
@@ -1424,3 +1552,24 @@
return 0;
}
+
+
+u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs)
+{
+ size_t i, j;
+ struct radius_attr_hdr *attr;
+
+ for (i = 0; i < msg->attr_used; i++) {
+ attr = radius_get_attr_hdr(msg, i);
+
+ for (j = 0; attrs[j]; j++) {
+ if (attr->type == attrs[j])
+ break;
+ }
+
+ if (attrs[j] == 0)
+ return attr->type; /* unlisted attr */
+ }
+
+ return 0;
+}
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 44123bd..2d059df 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -31,6 +31,12 @@
RADIUS_CODE_ACCESS_CHALLENGE = 11,
RADIUS_CODE_STATUS_SERVER = 12,
RADIUS_CODE_STATUS_CLIENT = 13,
+ RADIUS_CODE_DISCONNECT_REQUEST = 40,
+ RADIUS_CODE_DISCONNECT_ACK = 41,
+ RADIUS_CODE_DISCONNECT_NAK = 42,
+ RADIUS_CODE_COA_REQUEST = 43,
+ RADIUS_CODE_COA_ACK = 44,
+ RADIUS_CODE_COA_NAK = 45,
RADIUS_CODE_RESERVED = 255
};
@@ -83,7 +89,8 @@
RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81,
RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89,
- RADIUS_ATTR_NAS_IPV6_ADDRESS = 95
+ RADIUS_ATTR_NAS_IPV6_ADDRESS = 95,
+ RADIUS_ATTR_ERROR_CAUSE = 101
};
@@ -192,8 +199,15 @@
size_t secret_len);
int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
size_t secret_len, const u8 *req_authenticator);
+int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len,
+ const struct radius_hdr *req_hdr);
void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
size_t secret_len);
+int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len);
+int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len);
struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type,
const u8 *data, size_t data_len);
struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
@@ -268,4 +282,6 @@
int radius_copy_class(struct radius_class_data *dst,
const struct radius_class_data *src);
+u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs);
+
#endif /* RADIUS_H */
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index bcd471b..1ee7131 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -505,7 +505,7 @@
NULL);
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
- " %ld seconds\n", (long int) (first - now.sec));
+ " %ld seconds", (long int) (first - now.sec));
}
@@ -678,7 +678,7 @@
radius_client_list_add(radius, msg, msg_type, shared_secret,
shared_secret_len, addr);
- return res;
+ return 0;
}
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
new file mode 100644
index 0000000..8ecfffc
--- /dev/null
+++ b/src/radius/radius_das.c
@@ -0,0 +1,356 @@
+/*
+ * RADIUS Dynamic Authorization Server (DAS) (RFC 5176)
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <net/if.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/ip_addr.h"
+#include "radius.h"
+#include "radius_das.h"
+
+
+extern int wpa_debug_level;
+
+
+struct radius_das_data {
+ int sock;
+ u8 *shared_secret;
+ size_t shared_secret_len;
+ struct hostapd_ip_addr client_addr;
+ unsigned int time_window;
+ int require_event_timestamp;
+ void *ctx;
+ enum radius_das_res (*disconnect)(void *ctx,
+ struct radius_das_attrs *attr);
+};
+
+
+static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
+ struct radius_msg *msg,
+ const char *abuf,
+ int from_port)
+{
+ struct radius_hdr *hdr;
+ struct radius_msg *reply;
+ u8 allowed[] = {
+ RADIUS_ATTR_USER_NAME,
+ RADIUS_ATTR_CALLING_STATION_ID,
+ RADIUS_ATTR_ACCT_SESSION_ID,
+ RADIUS_ATTR_EVENT_TIMESTAMP,
+ RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ 0
+ };
+ int error = 405;
+ u8 attr;
+ enum radius_das_res res;
+ struct radius_das_attrs attrs;
+ u8 *buf;
+ size_t len;
+ char tmp[100];
+ u8 sta_addr[ETH_ALEN];
+
+ hdr = radius_msg_get_hdr(msg);
+
+ attr = radius_msg_find_unlisted_attr(msg, allowed);
+ if (attr) {
+ wpa_printf(MSG_INFO, "DAS: Unsupported attribute %u in "
+ "Disconnect-Request from %s:%d", attr,
+ abuf, from_port);
+ error = 401;
+ goto fail;
+ }
+
+ os_memset(&attrs, 0, sizeof(attrs));
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+ &buf, &len, NULL) == 0) {
+ if (len >= sizeof(tmp))
+ len = sizeof(tmp) - 1;
+ os_memcpy(tmp, buf, len);
+ tmp[len] = '\0';
+ if (hwaddr_aton2(tmp, sta_addr) < 0) {
+ wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
+ "'%s' from %s:%d", tmp, abuf, from_port);
+ error = 407;
+ goto fail;
+ }
+ attrs.sta_addr = sta_addr;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
+ &buf, &len, NULL) == 0) {
+ attrs.user_name = buf;
+ attrs.user_name_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+ &buf, &len, NULL) == 0) {
+ attrs.acct_session_id = buf;
+ attrs.acct_session_id_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ &buf, &len, NULL) == 0) {
+ attrs.cui = buf;
+ attrs.cui_len = len;
+ }
+
+ res = das->disconnect(das->ctx, &attrs);
+ switch (res) {
+ case RADIUS_DAS_NAS_MISMATCH:
+ wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
+ abuf, from_port);
+ error = 403;
+ break;
+ case RADIUS_DAS_SESSION_NOT_FOUND:
+ wpa_printf(MSG_INFO, "DAS: Session not found for request from "
+ "%s:%d", abuf, from_port);
+ error = 503;
+ break;
+ case RADIUS_DAS_SUCCESS:
+ error = 0;
+ break;
+ }
+
+fail:
+ reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK :
+ RADIUS_CODE_DISCONNECT_ACK, hdr->identifier);
+ if (reply == NULL)
+ return NULL;
+
+ if (error) {
+ radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
+ error);
+ }
+
+ return reply;
+}
+
+
+static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct radius_das_data *das = eloop_ctx;
+ u8 buf[1500];
+ union {
+ struct sockaddr_storage ss;
+ struct sockaddr_in sin;
+#ifdef CONFIG_IPV6
+ struct sockaddr_in6 sin6;
+#endif /* CONFIG_IPV6 */
+ } from;
+ char abuf[50];
+ int from_port = 0;
+ socklen_t fromlen;
+ int len;
+ struct radius_msg *msg, *reply = NULL;
+ struct radius_hdr *hdr;
+ struct wpabuf *rbuf;
+ u32 val;
+ int res;
+ struct os_time now;
+
+ fromlen = sizeof(from);
+ len = recvfrom(sock, buf, sizeof(buf), 0,
+ (struct sockaddr *) &from.ss, &fromlen);
+ if (len < 0) {
+ wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
+ return;
+ }
+
+ os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+ from_port = ntohs(from.sin.sin_port);
+
+ wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
+ len, abuf, from_port);
+ if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
+ wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
+ return;
+ }
+
+ msg = radius_msg_parse(buf, len);
+ if (msg == NULL) {
+ wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
+ "from %s:%d failed", abuf, from_port);
+ return;
+ }
+
+ if (wpa_debug_level <= MSG_MSGDUMP)
+ radius_msg_dump(msg);
+
+ if (radius_msg_verify_das_req(msg, das->shared_secret,
+ das->shared_secret_len)) {
+ wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet "
+ "from %s:%d - drop", abuf, from_port);
+ goto fail;
+ }
+
+ os_get_time(&now);
+ res = radius_msg_get_attr(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+ (u8 *) &val, 4);
+ if (res == 4) {
+ u32 timestamp = ntohl(val);
+ if (abs(now.sec - timestamp) > das->time_window) {
+ wpa_printf(MSG_DEBUG, "DAS: Unacceptable "
+ "Event-Timestamp (%u; local time %u) in "
+ "packet from %s:%d - drop",
+ timestamp, (unsigned int) now.sec,
+ abuf, from_port);
+ goto fail;
+ }
+ } else if (das->require_event_timestamp) {
+ wpa_printf(MSG_DEBUG, "DAS: Missing Event-Timestamp in packet "
+ "from %s:%d - drop", abuf, from_port);
+ goto fail;
+ }
+
+ hdr = radius_msg_get_hdr(msg);
+
+ switch (hdr->code) {
+ case RADIUS_CODE_DISCONNECT_REQUEST:
+ reply = radius_das_disconnect(das, msg, abuf, from_port);
+ break;
+ case RADIUS_CODE_COA_REQUEST:
+ /* TODO */
+ reply = radius_msg_new(RADIUS_CODE_COA_NAK,
+ hdr->identifier);
+ if (reply == NULL)
+ break;
+
+ /* Unsupported Service */
+ radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 405);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
+ "packet from %s:%d",
+ hdr->code, abuf, from_port);
+ }
+
+ if (reply) {
+ wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port);
+
+ if (!radius_msg_add_attr_int32(reply,
+ RADIUS_ATTR_EVENT_TIMESTAMP,
+ now.sec)) {
+ wpa_printf(MSG_DEBUG, "DAS: Failed to add "
+ "Event-Timestamp attribute");
+ }
+
+ if (radius_msg_finish_das_resp(reply, das->shared_secret,
+ das->shared_secret_len, hdr) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "DAS: Failed to add "
+ "Message-Authenticator attribute");
+ }
+
+ if (wpa_debug_level <= MSG_MSGDUMP)
+ radius_msg_dump(reply);
+
+ rbuf = radius_msg_get_buf(reply);
+ res = sendto(das->sock, wpabuf_head(rbuf),
+ wpabuf_len(rbuf), 0,
+ (struct sockaddr *) &from.ss, fromlen);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
+ abuf, from_port, strerror(errno));
+ }
+ }
+
+fail:
+ radius_msg_free(msg);
+ radius_msg_free(reply);
+}
+
+
+static int radius_das_open_socket(int port)
+{
+ int s;
+ struct sockaddr_in addr;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind");
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+
+struct radius_das_data *
+radius_das_init(struct radius_das_conf *conf)
+{
+ struct radius_das_data *das;
+
+ if (conf->port == 0 || conf->shared_secret == NULL ||
+ conf->client_addr == NULL)
+ return NULL;
+
+ das = os_zalloc(sizeof(*das));
+ if (das == NULL)
+ return NULL;
+
+ das->time_window = conf->time_window;
+ das->require_event_timestamp = conf->require_event_timestamp;
+ das->ctx = conf->ctx;
+ das->disconnect = conf->disconnect;
+
+ os_memcpy(&das->client_addr, conf->client_addr,
+ sizeof(das->client_addr));
+
+ das->shared_secret = os_malloc(conf->shared_secret_len);
+ if (das->shared_secret == NULL) {
+ radius_das_deinit(das);
+ return NULL;
+ }
+ os_memcpy(das->shared_secret, conf->shared_secret,
+ conf->shared_secret_len);
+ das->shared_secret_len = conf->shared_secret_len;
+
+ das->sock = radius_das_open_socket(conf->port);
+ if (das->sock < 0) {
+ wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
+ "DAS");
+ radius_das_deinit(das);
+ return NULL;
+ }
+
+ if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
+ {
+ radius_das_deinit(das);
+ return NULL;
+ }
+
+ return das;
+}
+
+
+void radius_das_deinit(struct radius_das_data *das)
+{
+ if (das == NULL)
+ return;
+
+ if (das->sock >= 0) {
+ eloop_unregister_read_sock(das->sock);
+ close(das->sock);
+ }
+
+ os_free(das->shared_secret);
+ os_free(das);
+}
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
new file mode 100644
index 0000000..738b18b
--- /dev/null
+++ b/src/radius/radius_das.h
@@ -0,0 +1,47 @@
+/*
+ * RADIUS Dynamic Authorization Server (DAS)
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RADIUS_DAS_H
+#define RADIUS_DAS_H
+
+struct radius_das_data;
+
+enum radius_das_res {
+ RADIUS_DAS_SUCCESS,
+ RADIUS_DAS_NAS_MISMATCH,
+ RADIUS_DAS_SESSION_NOT_FOUND
+};
+
+struct radius_das_attrs {
+ const u8 *sta_addr;
+ const u8 *user_name;
+ size_t user_name_len;
+ const u8 *acct_session_id;
+ size_t acct_session_id_len;
+ const u8 *cui;
+ size_t cui_len;
+};
+
+struct radius_das_conf {
+ int port;
+ const u8 *shared_secret;
+ size_t shared_secret_len;
+ const struct hostapd_ip_addr *client_addr;
+ unsigned int time_window;
+ int require_event_timestamp;
+ void *ctx;
+ enum radius_das_res (*disconnect)(void *ctx,
+ struct radius_das_attrs *attr);
+};
+
+struct radius_das_data *
+radius_das_init(struct radius_das_conf *conf);
+
+void radius_das_deinit(struct radius_das_data *data);
+
+#endif /* RADIUS_DAS_H */
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 6ebc37a..7646ca8 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -2202,7 +2202,9 @@
if (sm == NULL)
return -1;
- sm->l2_tdls = l2_packet_init(sm->ifname, sm->own_addr,
+ sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname :
+ sm->ifname,
+ sm->own_addr,
ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls,
sm, 0);
if (sm->l2_tdls == NULL) {
diff --git a/src/tls/libtommath.c b/src/tls/libtommath.c
index 7c9857f..741b442 100644
--- a/src/tls/libtommath.c
+++ b/src/tls/libtommath.c
@@ -66,11 +66,19 @@
#define OPT_CAST(x)
+#ifdef __x86_64__
+typedef unsigned long mp_digit;
+typedef unsigned long mp_word __attribute__((mode(TI)));
+
+#define DIGIT_BIT 60
+#define MP_64BIT
+#else
typedef unsigned long mp_digit;
typedef u64 mp_word;
#define DIGIT_BIT 28
#define MP_28BIT
+#endif
#define XMALLOC os_malloc
diff --git a/src/utils/build_config.h b/src/utils/build_config.h
index 04b8d98..f947388 100644
--- a/src/utils/build_config.h
+++ b/src/utils/build_config.h
@@ -47,28 +47,6 @@
#endif /* USE_INTERNAL_CRYPTO */
#endif /* CONFIG_WIN32_DEFAULTS */
-#ifdef __SYMBIAN32__
-#define OS_NO_C_LIB_DEFINES
-#define CONFIG_ANSI_C_EXTRA
-#define CONFIG_NO_WPA_MSG
-#define CONFIG_NO_HOSTAPD_LOGGER
-#define CONFIG_NO_STDOUT_DEBUG
-#define CONFIG_BACKEND_FILE
-#define CONFIG_INTERNAL_LIBTOMMATH
-#define CONFIG_CRYPTO_INTERNAL
-#define IEEE8021X_EAPOL
-#define PKCS12_FUNCS
-#define EAP_MD5
-#define EAP_TLS
-#define EAP_MSCHAPv2
-#define EAP_PEAP
-#define EAP_TTLS
-#define EAP_GTC
-#define EAP_OTP
-#define EAP_LEAP
-#define EAP_FAST
-#endif /* __SYMBIAN32__ */
-
#ifdef CONFIG_XCODE_DEFAULTS
#define CONFIG_DRIVER_OSX
#define CONFIG_BACKEND_FILE
diff --git a/src/utils/common.h b/src/utils/common.h
index 43ceb54..7f115ef 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -63,12 +63,6 @@
#endif
#endif /* CONFIG_TI_COMPILER */
-#ifdef __SYMBIAN32__
-#define __BIG_ENDIAN 4321
-#define __LITTLE_ENDIAN 1234
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif /* __SYMBIAN32__ */
-
#ifdef CONFIG_NATIVE_WINDOWS
#include <winsock.h>
@@ -132,16 +126,6 @@
#define WPA_TYPES_DEFINED
#endif /* CONFIG_TI_COMPILER */
-#ifdef __SYMBIAN32__
-#define __REMOVE_PLATSEC_DIAGNOSTICS__
-#include <e32def.h>
-typedef TUint64 u64;
-typedef TUint32 u32;
-typedef TUint16 u16;
-typedef TUint8 u8;
-#define WPA_TYPES_DEFINED
-#endif /* __SYMBIAN32__ */
-
#ifndef WPA_TYPES_DEFINED
#ifdef CONFIG_USE_INTTYPES_H
#include <inttypes.h>
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index 5691f15..bb32401 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -278,7 +278,7 @@
pollfds_map[fd] = pfd;
nxt++;
}
- pfd->events |= POLLIN;
+ pfd->events |= POLLOUT;
}
}
@@ -350,7 +350,8 @@
int max_pollfd_map)
{
if (eloop_sock_table_dispatch_table(readers, pollfds_map,
- max_pollfd_map, POLLIN))
+ max_pollfd_map, POLLIN | POLLERR |
+ POLLHUP))
return; /* pollfds may be invalid at this point */
if (eloop_sock_table_dispatch_table(writers, pollfds_map,
diff --git a/src/utils/includes.h b/src/utils/includes.h
index 787be18..6c6ec87 100644
--- a/src/utils/includes.h
+++ b/src/utils/includes.h
@@ -41,9 +41,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef __vxworks
-#ifndef __SYMBIAN32__
#include <sys/uio.h>
-#endif /* __SYMBIAN32__ */
#include <sys/time.h>
#endif /* __vxworks */
#endif /* CONFIG_TI_COMPILER */
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
index a97f9fa..08510d0 100644
--- a/src/utils/pcsc_funcs.c
+++ b/src/utils/pcsc_funcs.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2007, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -70,6 +70,9 @@
#define USIM_TLV_TOTAL_FILE_SIZE 0x81
#define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6
#define USIM_TLV_SHORT_FILE_ID 0x88
+#define USIM_TLV_SECURITY_ATTR_8B 0x8B
+#define USIM_TLV_SECURITY_ATTR_8C 0x8C
+#define USIM_TLV_SECURITY_ATTR_AB 0xAB
#define USIM_PS_DO_TAG 0x90
@@ -81,6 +84,27 @@
#define CK_LEN 16
+/* GSM files
+ * File type in first octet:
+ * 3F = Master File
+ * 7F = Dedicated File
+ * 2F = Elementary File under the Master File
+ * 6F = Elementary File under a Dedicated File
+ */
+#define SCARD_FILE_MF 0x3F00
+#define SCARD_FILE_GSM_DF 0x7F20
+#define SCARD_FILE_UMTS_DF 0x7F50
+#define SCARD_FILE_GSM_EF_IMSI 0x6F07
+#define SCARD_FILE_GSM_EF_AD 0x6FAD
+#define SCARD_FILE_EF_DIR 0x2F00
+#define SCARD_FILE_EF_ICCID 0x2FE2
+#define SCARD_FILE_EF_CK 0x6FE1
+#define SCARD_FILE_EF_IK 0x6FE2
+
+#define SCARD_CHV1_OFFSET 13
+#define SCARD_CHV1_FLAG 0x80
+
+
typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
struct scard_data {
@@ -234,37 +258,60 @@
static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
int *ps_do, int *file_len)
{
- unsigned char *pos, *end;
+ unsigned char *pos, *end;
- if (ps_do)
- *ps_do = -1;
- if (file_len)
- *file_len = -1;
+ if (ps_do)
+ *ps_do = -1;
+ if (file_len)
+ *file_len = -1;
- pos = buf;
- end = pos + buf_len;
- if (*pos != USIM_FSP_TEMPL_TAG) {
- wpa_printf(MSG_DEBUG, "SCARD: file header did not "
- "start with FSP template tag");
- return -1;
- }
- pos++;
- if (pos >= end)
- return -1;
- if ((pos + pos[0]) < end)
- end = pos + 1 + pos[0];
- pos++;
- wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
- pos, end - pos);
+ pos = buf;
+ end = pos + buf_len;
+ if (*pos != USIM_FSP_TEMPL_TAG) {
+ wpa_printf(MSG_DEBUG, "SCARD: file header did not "
+ "start with FSP template tag");
+ return -1;
+ }
+ pos++;
+ if (pos >= end)
+ return -1;
+ if ((pos + pos[0]) < end)
+ end = pos + 1 + pos[0];
+ pos++;
+ wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
+ pos, end - pos);
- while (pos + 1 < end) {
- wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV "
- "0x%02x len=%d", pos[0], pos[1]);
- if (pos + 2 + pos[1] > end)
- break;
+ while (pos + 1 < end) {
+ wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV 0x%02x len=%d",
+ pos[0], pos[1]);
+ if (pos + 2 + pos[1] > end)
+ break;
- if (pos[0] == USIM_TLV_FILE_SIZE &&
- (pos[1] == 1 || pos[1] == 2) && file_len) {
+ switch (pos[0]) {
+ case USIM_TLV_FILE_DESC:
+ wpa_hexdump(MSG_MSGDUMP, "SCARD: File Descriptor TLV",
+ pos + 2, pos[1]);
+ break;
+ case USIM_TLV_FILE_ID:
+ wpa_hexdump(MSG_MSGDUMP, "SCARD: File Identifier TLV",
+ pos + 2, pos[1]);
+ break;
+ case USIM_TLV_DF_NAME:
+ wpa_hexdump(MSG_MSGDUMP, "SCARD: DF name (AID) TLV",
+ pos + 2, pos[1]);
+ break;
+ case USIM_TLV_PROPR_INFO:
+ wpa_hexdump(MSG_MSGDUMP, "SCARD: Proprietary "
+ "information TLV", pos + 2, pos[1]);
+ break;
+ case USIM_TLV_LIFE_CYCLE_STATUS:
+ wpa_hexdump(MSG_MSGDUMP, "SCARD: Life Cycle Status "
+ "Integer TLV", pos + 2, pos[1]);
+ break;
+ case USIM_TLV_FILE_SIZE:
+ wpa_hexdump(MSG_MSGDUMP, "SCARD: File size TLV",
+ pos + 2, pos[1]);
+ if ((pos[1] == 1 || pos[1] == 2) && file_len) {
if (pos[1] == 1)
*file_len = (int) pos[2];
else
@@ -273,21 +320,43 @@
wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
*file_len);
}
-
- if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE &&
- pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
+ break;
+ case USIM_TLV_TOTAL_FILE_SIZE:
+ wpa_hexdump(MSG_MSGDUMP, "SCARD: Total file size TLV",
+ pos + 2, pos[1]);
+ break;
+ case USIM_TLV_PIN_STATUS_TEMPLATE:
+ wpa_hexdump(MSG_MSGDUMP, "SCARD: PIN Status Template "
+ "DO TLV", pos + 2, pos[1]);
+ if (pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
pos[3] >= 1 && ps_do) {
wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
pos[4]);
*ps_do = (int) pos[4];
}
-
- pos += 2 + pos[1];
-
- if (pos == end)
- return 0;
+ break;
+ case USIM_TLV_SHORT_FILE_ID:
+ wpa_hexdump(MSG_MSGDUMP, "SCARD: Short File "
+ "Identifier (SFI) TLV", pos + 2, pos[1]);
+ break;
+ case USIM_TLV_SECURITY_ATTR_8B:
+ case USIM_TLV_SECURITY_ATTR_8C:
+ case USIM_TLV_SECURITY_ATTR_AB:
+ wpa_hexdump(MSG_MSGDUMP, "SCARD: Security attribute "
+ "TLV", pos + 2, pos[1]);
+ break;
+ default:
+ wpa_hexdump(MSG_MSGDUMP, "SCARD: Unrecognized TLV",
+ pos, 2 + pos[1]);
+ break;
}
- return -1;
+
+ pos += 2 + pos[1];
+
+ if (pos == end)
+ return 0;
+ }
+ return -1;
}
@@ -328,7 +397,7 @@
unsigned char rid[5];
unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
} *efdir;
- unsigned char buf[100];
+ unsigned char buf[127];
size_t blen;
efdir = (struct efdir *) buf;
@@ -417,6 +486,7 @@
/**
* scard_init - Initialize SIM/USIM connection using PC/SC
* @sim_type: Allowed SIM types (SIM, USIM, or both)
+ * @reader: Reader name prefix to search for
* Returns: Pointer to private data structure, or %NULL on failure
*
* This function is used to initialize SIM/USIM connection. PC/SC is used to
@@ -425,10 +495,10 @@
* access some of the card functions. Once the connection is not needed
* anymore, scard_deinit() can be used to close it.
*/
-struct scard_data * scard_init(scard_sim_type sim_type)
+struct scard_data * scard_init(scard_sim_type sim_type, const char *reader)
{
long ret;
- unsigned long len;
+ unsigned long len, pos;
struct scard_data *scard;
#ifdef CONFIG_NATIVE_WINDOWS
TCHAR *readers = NULL;
@@ -482,18 +552,41 @@
"available.");
goto failed;
}
- /* readers is a list of available reader. Last entry is terminated with
- * double NUL.
- * TODO: add support for selecting the reader; now just use the first
- * one.. */
+ wpa_hexdump_ascii(MSG_DEBUG, "SCARD: Readers", (u8 *) readers, len);
+ /*
+ * readers is a list of available readers. The last entry is terminated
+ * with double null.
+ */
+ pos = 0;
#ifdef UNICODE
- wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers);
+ /* TODO */
#else /* UNICODE */
- wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers);
+ while (pos < len) {
+ if (reader == NULL ||
+ os_strncmp(&readers[pos], reader, os_strlen(reader)) == 0)
+ break;
+ while (pos < len && readers[pos])
+ pos++;
+ pos++; /* skip separating null */
+ if (pos < len && readers[pos] == '\0')
+ pos = len; /* double null terminates list */
+ }
+#endif /* UNICODE */
+ if (pos >= len) {
+ wpa_printf(MSG_WARNING, "SCARD: No reader with prefix '%s' "
+ "found", reader);
+ goto failed;
+ }
+
+#ifdef UNICODE
+ wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", &readers[pos]);
+#else /* UNICODE */
+ wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", &readers[pos]);
#endif /* UNICODE */
- ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED,
- SCARD_PROTOCOL_T0, &scard->card, &scard->protocol);
+ ret = SCardConnect(scard->ctx, &readers[pos], SCARD_SHARE_SHARED,
+ SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+ &scard->card, &scard->protocol);
if (ret != SCARD_S_SUCCESS) {
if (ret == (long) SCARD_E_NO_SMARTCARD)
wpa_printf(MSG_INFO, "No smart card inserted.");
@@ -582,7 +675,8 @@
}
if (pin_needed) {
scard->pin1_required = 1;
- wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
+ wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access (retry "
+ "counter=%d)", scard_get_pin_retry_counter(scard));
}
ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
@@ -939,6 +1033,46 @@
}
+int scard_get_pin_retry_counter(struct scard_data *scard)
+{
+ long ret;
+ unsigned char resp[3];
+ unsigned char cmd[5] = { SIM_CMD_VERIFY_CHV1 };
+ size_t len;
+ u16 val;
+
+ wpa_printf(MSG_DEBUG, "SCARD: fetching PIN retry counter");
+
+ if (scard->sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ cmd[4] = 0; /* Empty data */
+
+ len = sizeof(resp);
+ ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
+ if (ret != SCARD_S_SUCCESS)
+ return -2;
+
+ if (len != 2) {
+ wpa_printf(MSG_WARNING, "SCARD: failed to fetch PIN retry "
+ "counter");
+ return -1;
+ }
+
+ val = WPA_GET_BE16(resp);
+ if (val == 0x63c0 || val == 0x6983) {
+ wpa_printf(MSG_DEBUG, "SCARD: PIN has been blocked");
+ return 0;
+ }
+
+ if (val >= 0x63c0 && val <= 0x63cf)
+ return val & 0x000f;
+
+ wpa_printf(MSG_DEBUG, "SCARD: Unexpected PIN retry counter response "
+ "value 0x%x", val);
+ return 0;
+}
+
+
/**
* scard_get_imsi - Read IMSI from SIM/USIM card
* @scard: Pointer to private data from scard_init()
@@ -1285,3 +1419,9 @@
wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response");
return -1;
}
+
+
+int scard_supports_umts(struct scard_data *scard)
+{
+ return scard->sim_type == SCARD_USIM;
+}
diff --git a/src/utils/pcsc_funcs.h b/src/utils/pcsc_funcs.h
index 2fd3610..b4ebc99 100644
--- a/src/utils/pcsc_funcs.h
+++ b/src/utils/pcsc_funcs.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2006, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,26 +9,6 @@
#ifndef PCSC_FUNCS_H
#define PCSC_FUNCS_H
-/* GSM files
- * File type in first octet:
- * 3F = Master File
- * 7F = Dedicated File
- * 2F = Elementary File under the Master File
- * 6F = Elementary File under a Dedicated File
- */
-#define SCARD_FILE_MF 0x3F00
-#define SCARD_FILE_GSM_DF 0x7F20
-#define SCARD_FILE_UMTS_DF 0x7F50
-#define SCARD_FILE_GSM_EF_IMSI 0x6F07
-#define SCARD_FILE_GSM_EF_AD 0x6FAD
-#define SCARD_FILE_EF_DIR 0x2F00
-#define SCARD_FILE_EF_ICCID 0x2FE2
-#define SCARD_FILE_EF_CK 0x6FE1
-#define SCARD_FILE_EF_IK 0x6FE2
-
-#define SCARD_CHV1_OFFSET 13
-#define SCARD_CHV1_FLAG 0x80
-
typedef enum {
SCARD_GSM_SIM_ONLY,
SCARD_USIM_ONLY,
@@ -37,7 +17,7 @@
#ifdef PCSC_FUNCS
-struct scard_data * scard_init(scard_sim_type sim_type);
+struct scard_data * scard_init(scard_sim_type sim_type, const char *reader);
void scard_deinit(struct scard_data *scard);
int scard_set_pin(struct scard_data *scard, const char *pin);
@@ -49,15 +29,20 @@
const unsigned char *autn,
unsigned char *res, size_t *res_len,
unsigned char *ik, unsigned char *ck, unsigned char *auts);
+int scard_get_pin_retry_counter(struct scard_data *scard);
+int scard_supports_umts(struct scard_data *scard);
#else /* PCSC_FUNCS */
-#define scard_init(s) NULL
+#define scard_init(s, r) NULL
#define scard_deinit(s) do { } while (0)
#define scard_set_pin(s, p) -1
#define scard_get_imsi(s, i, l) -1
+#define scard_get_mnc_len(s) -1
#define scard_gsm_auth(s, r, s2, k) -1
#define scard_umts_auth(s, r, a, r2, rl, i, c, a2) -1
+#define scard_get_pin_retry_counter(s) -1
+#define scard_supports_umts(s) 0
#endif /* PCSC_FUNCS */
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index a8b9106..5511ef1 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -16,6 +16,18 @@
static int wpa_debug_syslog = 0;
#endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+
+static FILE *wpa_debug_tracing_file = NULL;
+
+#define WPAS_TRACE_PFX "wpas <%d>: "
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
int wpa_debug_level = MSG_INFO;
int wpa_debug_show_keys = 0;
@@ -30,25 +42,18 @@
#define ANDROID_LOG_NAME "wpa_supplicant"
#endif /* ANDROID_LOG_NAME */
-void android_printf(int level, char *format, ...)
+static int wpa_to_android_level(int level)
{
- if (level >= wpa_debug_level) {
- va_list ap;
- if (level == MSG_ERROR)
- level = ANDROID_LOG_ERROR;
- else if (level == MSG_WARNING)
- level = ANDROID_LOG_WARN;
- else if (level == MSG_INFO)
- level = ANDROID_LOG_INFO;
- else
- level = ANDROID_LOG_DEBUG;
- va_start(ap, format);
- __android_log_vprint(level, ANDROID_LOG_NAME, format, ap);
- va_end(ap);
- }
+ if (level == MSG_ERROR)
+ return ANDROID_LOG_ERROR;
+ if (level == MSG_WARNING)
+ return ANDROID_LOG_WARN;
+ if (level == MSG_INFO)
+ return ANDROID_LOG_INFO;
+ return ANDROID_LOG_DEBUG;
}
-#else /* CONFIG_ANDROID_LOG */
+#endif /* CONFIG_ANDROID_LOG */
#ifndef CONFIG_NO_STDOUT_DEBUG
@@ -59,6 +64,7 @@
void wpa_debug_print_timestamp(void)
{
+#ifndef CONFIG_ANDROID_LOG
struct os_time tv;
if (!wpa_debug_timestamp)
@@ -72,6 +78,7 @@
} else
#endif /* CONFIG_DEBUG_FILE */
printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
+#endif /* CONFIG_ANDROID_LOG */
}
@@ -112,6 +119,77 @@
#endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+
+int wpa_debug_open_linux_tracing(void)
+{
+ int mounts, trace_fd;
+ char buf[4096] = {};
+ ssize_t buflen;
+ char *line, *tmp1, *path = NULL;
+
+ mounts = open("/proc/mounts", O_RDONLY);
+ if (mounts < 0) {
+ printf("no /proc/mounts\n");
+ return -1;
+ }
+
+ buflen = read(mounts, buf, sizeof(buf) - 1);
+ close(mounts);
+ if (buflen < 0) {
+ printf("failed to read /proc/mounts\n");
+ return -1;
+ }
+
+ line = strtok_r(buf, "\n", &tmp1);
+ while (line) {
+ char *tmp2, *tmp_path, *fstype;
+ /* "<dev> <mountpoint> <fs type> ..." */
+ strtok_r(line, " ", &tmp2);
+ tmp_path = strtok_r(NULL, " ", &tmp2);
+ fstype = strtok_r(NULL, " ", &tmp2);
+ if (strcmp(fstype, "debugfs") == 0) {
+ path = tmp_path;
+ break;
+ }
+
+ line = strtok_r(NULL, "\n", &tmp1);
+ }
+
+ if (path == NULL) {
+ printf("debugfs mountpoint not found\n");
+ return -1;
+ }
+
+ snprintf(buf, sizeof(buf) - 1, "%s/tracing/trace_marker", path);
+
+ trace_fd = open(buf, O_WRONLY);
+ if (trace_fd < 0) {
+ printf("failed to open trace_marker file\n");
+ return -1;
+ }
+ wpa_debug_tracing_file = fdopen(trace_fd, "w");
+ if (wpa_debug_tracing_file == NULL) {
+ close(trace_fd);
+ printf("failed to fdopen()\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void wpa_debug_close_linux_tracing(void)
+{
+ if (wpa_debug_tracing_file == NULL)
+ return;
+ fclose(wpa_debug_tracing_file);
+ wpa_debug_tracing_file = NULL;
+}
+
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
+
/**
* wpa_printf - conditional printf
* @level: priority level (MSG_*) of the message
@@ -129,6 +207,10 @@
va_start(ap, fmt);
if (level >= wpa_debug_level) {
+#ifdef CONFIG_ANDROID_LOG
+ __android_log_vprint(wpa_to_android_level(level),
+ ANDROID_LOG_NAME, fmt, ap);
+#else /* CONFIG_ANDROID_LOG */
#ifdef CONFIG_DEBUG_SYSLOG
if (wpa_debug_syslog) {
vsyslog(syslog_priority(level), fmt, ap);
@@ -149,8 +231,20 @@
#ifdef CONFIG_DEBUG_SYSLOG
}
#endif /* CONFIG_DEBUG_SYSLOG */
+#endif /* CONFIG_ANDROID_LOG */
}
va_end(ap);
+
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ if (wpa_debug_tracing_file != NULL) {
+ va_start(ap, fmt);
+ fprintf(wpa_debug_tracing_file, WPAS_TRACE_PFX, level);
+ vfprintf(wpa_debug_tracing_file, fmt, ap);
+ fprintf(wpa_debug_tracing_file, "\n");
+ fflush(wpa_debug_tracing_file);
+ va_end(ap);
+ }
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
}
@@ -158,8 +252,65 @@
size_t len, int show)
{
size_t i;
+
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ if (wpa_debug_tracing_file != NULL) {
+ fprintf(wpa_debug_tracing_file,
+ WPAS_TRACE_PFX "%s - hexdump(len=%lu):",
+ level, title, (unsigned long) len);
+ if (buf == NULL) {
+ fprintf(wpa_debug_tracing_file, " [NULL]\n");
+ } else if (!show) {
+ fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
+ } else {
+ for (i = 0; i < len; i++)
+ fprintf(wpa_debug_tracing_file,
+ " %02x", buf[i]);
+ }
+ fflush(wpa_debug_tracing_file);
+ }
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
if (level < wpa_debug_level)
return;
+#ifdef CONFIG_ANDROID_LOG
+ {
+ const char *display;
+ char *strbuf = NULL;
+ size_t slen = len;
+ if (buf == NULL) {
+ display = " [NULL]";
+ } else if (len == 0) {
+ display = "";
+ } else if (show && len) {
+ /* Limit debug message length for Android log */
+ if (slen > 32)
+ slen = 32;
+ strbuf = os_malloc(1 + 3 * slen);
+ if (strbuf == NULL) {
+ wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
+ "allocate message buffer");
+ return;
+ }
+
+ for (i = 0; i < slen; i++)
+ os_snprintf(&strbuf[i * 3], 4, " %02x",
+ buf[i]);
+
+ display = strbuf;
+ } else {
+ display = " [REMOVED]";
+ }
+
+ __android_log_print(wpa_to_android_level(level),
+ ANDROID_LOG_NAME,
+ "%s - hexdump(len=%lu):%s%s",
+ title, (long unsigned int) len, display,
+ len > slen ? " ..." : "");
+ os_free(strbuf);
+ return;
+ }
+#else /* CONFIG_ANDROID_LOG */
#ifdef CONFIG_DEBUG_SYSLOG
if (wpa_debug_syslog) {
const char *display;
@@ -187,7 +338,7 @@
}
syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
- title, len, display);
+ title, (unsigned long) len, display);
os_free(strbuf);
return;
}
@@ -221,6 +372,7 @@
#ifdef CONFIG_DEBUG_FILE
}
#endif /* CONFIG_DEBUG_FILE */
+#endif /* CONFIG_ANDROID_LOG */
}
void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
@@ -242,8 +394,30 @@
const u8 *pos = buf;
const size_t line_len = 16;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ if (wpa_debug_tracing_file != NULL) {
+ fprintf(wpa_debug_tracing_file,
+ WPAS_TRACE_PFX "%s - hexdump_ascii(len=%lu):",
+ level, title, (unsigned long) len);
+ if (buf == NULL) {
+ fprintf(wpa_debug_tracing_file, " [NULL]\n");
+ } else if (!show) {
+ fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
+ } else {
+ /* can do ascii processing in userspace */
+ for (i = 0; i < len; i++)
+ fprintf(wpa_debug_tracing_file,
+ " %02x", buf[i]);
+ }
+ fflush(wpa_debug_tracing_file);
+ }
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
if (level < wpa_debug_level)
return;
+#ifdef CONFIG_ANDROID_LOG
+ _wpa_hexdump(level, title, buf, len, show);
+#else /* CONFIG_ANDROID_LOG */
wpa_debug_print_timestamp();
#ifdef CONFIG_DEBUG_FILE
if (out_file) {
@@ -317,6 +491,7 @@
#ifdef CONFIG_DEBUG_FILE
}
#endif /* CONFIG_DEBUG_FILE */
+#endif /* CONFIG_ANDROID_LOG */
}
@@ -398,7 +573,6 @@
#endif /* CONFIG_NO_STDOUT_DEBUG */
-#endif /* CONFIG_ANDROID_LOG */
#ifndef CONFIG_NO_WPA_MSG
static wpa_msg_cb_func wpa_msg_cb = NULL;
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index bbef49b..339c749 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -18,32 +18,6 @@
MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR
};
-#ifdef CONFIG_ANDROID_LOG
-
-#define wpa_debug_print_timestamp() do {} while (0)
-#define wpa_hexdump(...) do {} while (0)
-#define wpa_hexdump_key(...) do {} while (0)
-#define wpa_hexdump_buf(l,t,b) do {} while (0)
-#define wpa_hexdump_buf_key(l,t,b) do {} while (0)
-#define wpa_hexdump_ascii(...) do {} while (0)
-#define wpa_hexdump_ascii_key(...) do {} while (0)
-#define wpa_debug_open_file(...) do {} while (0)
-#define wpa_debug_close_file() do {} while (0)
-#define wpa_dbg(...) do {} while (0)
-
-static inline int wpa_debug_reopen_file(void)
-{
- return 0;
-}
-
-
-void android_printf(int level, char *format, ...)
-PRINTF_FORMAT(2, 3);
-
-#define wpa_printf android_printf
-
-#else /* CONFIG_ANDROID_LOG */
-
#ifdef CONFIG_NO_STDOUT_DEBUG
#define wpa_debug_print_timestamp() do { } while (0)
@@ -177,8 +151,6 @@
#endif /* CONFIG_NO_STDOUT_DEBUG */
-#endif /* CONFIG_ANDROID_LOG */
-
#ifdef CONFIG_NO_WPA_MSG
#define wpa_msg(args...) do { } while (0)
@@ -283,6 +255,24 @@
#endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+
+int wpa_debug_open_linux_tracing(void);
+void wpa_debug_close_linux_tracing(void);
+
+#else /* CONFIG_DEBUG_LINUX_TRACING */
+
+static inline int wpa_debug_open_linux_tracing(void)
+{
+ return 0;
+}
+
+static inline void wpa_debug_close_linux_tracing(void)
+{
+}
+
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
#ifdef EAPOL_TEST
#define WPA_ASSERT(a) \
diff --git a/src/wps/ndef.c b/src/wps/ndef.c
index 9baec7f..7630ecb 100644
--- a/src/wps/ndef.c
+++ b/src/wps/ndef.c
@@ -1,16 +1,10 @@
/*
* NDEF(NFC Data Exchange Format) routines for Wi-Fi Protected Setup
* Reference is "NFCForum-TS-NDEF_1.0 2006-07-24".
- * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp>
+ * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com>
*
- * 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 "includes.h"
@@ -26,9 +20,9 @@
#define FLAG_TNF_RFC2046 (0x02)
struct ndef_record {
- u8 *type;
- u8 *id;
- u8 *payload;
+ const u8 *type;
+ const u8 *id;
+ const u8 *payload;
u8 type_length;
u8 id_length;
u32 payload_length;
@@ -37,9 +31,10 @@
static char wifi_handover_type[] = "application/vnd.wfa.wsc";
-static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record)
+static int ndef_parse_record(const u8 *data, u32 size,
+ struct ndef_record *record)
{
- u8 *pos = data + 1;
+ const u8 *pos = data + 1;
if (size < 2)
return -1;
@@ -78,12 +73,12 @@
}
-static struct wpabuf * ndef_parse_records(struct wpabuf *buf,
+static struct wpabuf * ndef_parse_records(const struct wpabuf *buf,
int (*filter)(struct ndef_record *))
{
struct ndef_record record;
int len = wpabuf_len(buf);
- u8 *data = wpabuf_mhead(buf);
+ const u8 *data = wpabuf_head(buf);
while (len > 0) {
if (ndef_parse_record(data, len, &record) < 0) {
@@ -103,13 +98,14 @@
static struct wpabuf * ndef_build_record(u8 flags, void *type,
u8 type_length, void *id,
- u8 id_length, void *payload,
- u32 payload_length)
+ u8 id_length,
+ const struct wpabuf *payload)
{
struct wpabuf *record;
size_t total_len;
int short_record;
u8 local_flag;
+ size_t payload_length = wpabuf_len(payload);
short_record = payload_length < 256 ? 1 : 0;
@@ -144,7 +140,7 @@
wpabuf_put_u8(record, id_length);
wpabuf_put_data(record, type, type_length);
wpabuf_put_data(record, id, id_length);
- wpabuf_put_data(record, payload, payload_length);
+ wpabuf_put_buf(record, payload);
return record;
}
@@ -160,16 +156,15 @@
}
-struct wpabuf * ndef_parse_wifi(struct wpabuf *buf)
+struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf)
{
return ndef_parse_records(buf, wifi_filter);
}
-struct wpabuf * ndef_build_wifi(struct wpabuf *buf)
+struct wpabuf * ndef_build_wifi(const struct wpabuf *buf)
{
return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END |
FLAG_TNF_RFC2046, wifi_handover_type,
- os_strlen(wifi_handover_type), NULL, 0,
- wpabuf_mhead(buf), wpabuf_len(buf));
+ os_strlen(wifi_handover_type), NULL, 0, buf);
}
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 9422c71..5453962 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -56,6 +56,23 @@
data->dev_password_len = cfg->pin_len;
}
+#ifdef CONFIG_WPS_NFC
+ if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
+ data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id;
+ os_free(data->dev_password);
+ data->dev_password =
+ os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw));
+ if (data->dev_password == NULL) {
+ os_free(data);
+ return NULL;
+ }
+ os_memcpy(data->dev_password,
+ wpabuf_head(cfg->wps->ap_nfc_dev_pw),
+ wpabuf_len(cfg->wps->ap_nfc_dev_pw));
+ data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw);
+ }
+#endif /* CONFIG_WPS_NFC */
+
data->pbc = cfg->pbc;
if (cfg->pbc) {
/* Use special PIN '00000000' for PBC */
@@ -118,6 +135,12 @@
*/
void wps_deinit(struct wps_data *data)
{
+#ifdef CONFIG_WPS_NFC
+ if (data->registrar && data->nfc_pw_token)
+ wps_registrar_remove_nfc_pw_token(data->wps->registrar,
+ data->nfc_pw_token);
+#endif /* CONFIG_WPS_NFC */
+
if (data->wps_pin_revealed) {
wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and "
"negotiation failed");
@@ -136,6 +159,7 @@
wps_device_data_free(&data->peer_dev);
os_free(data->new_ap_settings);
dh5_free(data->dh_ctx);
+ os_free(data->nfc_pw_token);
os_free(data);
}
@@ -431,7 +455,8 @@
/**
* wps_build_probe_req_ie - Build WPS IE for Probe Request
- * @pbc: Whether searching for PBC mode APs
+ * @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for
+ * most other use cases)
* @dev: Device attributes
* @uuid: Own UUID
* @req_type: Value for Request Type attribute
@@ -442,7 +467,7 @@
*
* The caller is responsible for freeing the buffer.
*/
-struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
+struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
const u8 *uuid,
enum wps_request_type req_type,
unsigned int num_req_dev_types,
@@ -464,8 +489,7 @@
wps_build_rf_bands(dev, ie) ||
wps_build_assoc_state(NULL, ie) ||
wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
- wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON :
- DEV_PW_DEFAULT) ||
+ wps_build_dev_password_id(ie, pw_id) ||
#ifdef CONFIG_WPS2
wps_build_manufacturer(dev, ie) ||
wps_build_model_name(dev, ie) ||
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 22e029f..c45b68c 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -1,6 +1,6 @@
/*
* Wi-Fi Protected Setup
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,6 +27,7 @@
struct wps_registrar;
struct upnp_wps_device_sm;
struct wps_er;
+struct wps_parse_attr;
/**
* struct wps_credential - WPS Credential
@@ -94,6 +95,7 @@
u32 os_version;
u8 rf_bands;
u16 config_methods;
+ struct wpabuf *vendor_ext_m1;
struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
int p2p;
@@ -238,7 +240,7 @@
struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
struct wpabuf * wps_build_assoc_resp_ie(void);
-struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
+struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
const u8 *uuid,
enum wps_request_type req_type,
unsigned int num_req_dev_types,
@@ -294,12 +296,15 @@
* @ctx: Higher layer context data (cb_ctx)
* @mac_addr: MAC address of the Enrollee
* @uuid_e: UUID-E of the Enrollee
+ * @dev_pw: Device Password (PIN) used during registration
+ * @dev_pw_len: Length of dev_pw in octets
*
* This callback is called whenever an Enrollee completes registration
* successfully.
*/
void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
- const u8 *uuid_e);
+ const u8 *uuid_e, const u8 *dev_pw,
+ size_t dev_pw_len);
/**
* set_sel_reg_cb - Callback for reporting selected registrar changes
@@ -752,6 +757,11 @@
/* Pending messages from UPnP PutWLANResponse */
struct upnp_pending_message *upnp_msgs;
+
+ u16 ap_nfc_dev_pw_id;
+ struct wpabuf *ap_nfc_dh_pubkey;
+ struct wpabuf *ap_nfc_dh_privkey;
+ struct wpabuf *ap_nfc_dev_pw;
};
struct oob_device_data {
@@ -783,7 +793,8 @@
int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
int wps_registrar_button_pushed(struct wps_registrar *reg,
const u8 *p2p_dev_addr);
-void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e);
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,
+ const u8 *dev_pw, size_t dev_pw_len);
void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
const struct wpabuf *wps_data,
int p2p_wildcard);
@@ -792,6 +803,12 @@
char *buf, size_t buflen);
int wps_registrar_config_ap(struct wps_registrar *reg,
struct wps_credential *cred);
+int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
+ const u8 *pubkey_hash, u16 pw_id,
+ const u8 *dev_pw, size_t dev_pw_len);
+int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
+ const u8 *oob_dev_pw,
+ size_t oob_dev_pw_len);
int wps_build_credential_wrap(struct wpabuf *msg,
const struct wps_credential *cred);
@@ -799,6 +816,7 @@
unsigned int wps_pin_checksum(unsigned int pin);
unsigned int wps_pin_valid(unsigned int pin);
unsigned int wps_generate_pin(void);
+int wps_pin_str_valid(const char *pin);
void wps_free_pending_msgs(struct upnp_pending_message *msgs);
struct oob_device_data * wps_get_oob_device(char *device_type);
@@ -806,6 +824,8 @@
int wps_get_oob_method(char *method);
int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
int registrar);
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps);
+int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr);
int wps_attr_text(struct wpabuf *data, char *buf, char *end);
struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname,
@@ -821,12 +841,23 @@
const struct wps_credential *cred);
int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
size_t pin_len, const struct wps_credential *cred);
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid);
int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]);
char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
size_t buf_len);
void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid);
u16 wps_config_methods_str2bin(const char *str);
+struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
+ const struct wpabuf *pubkey,
+ const struct wpabuf *dev_pw);
+struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
+ struct wpabuf **privkey,
+ struct wpabuf **dev_pw);
+
+/* ndef.c */
+struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
+struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
#ifdef CONFIG_WPS_STRICT
int wps_validate_beacon(const struct wpabuf *wps_ie);
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index 753083d..9be30b9 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -30,6 +30,14 @@
wps->dh_ctx = wps->wps->dh_ctx;
wps->wps->dh_ctx = NULL;
pubkey = wpabuf_dup(wps->wps->dh_pubkey);
+#ifdef CONFIG_WPS_NFC
+ } else if (wps->dev_pw_id >= 0x10 && wps->wps->ap &&
+ wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) {
+ wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
+ wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
+ pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
+ wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
+#endif /* CONFIG_WPS_NFC */
} else {
wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
wps->dh_privkey = NULL;
@@ -340,19 +348,34 @@
#ifdef CONFIG_WPS_OOB
-int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
+int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
+ const struct wpabuf *pubkey, const u8 *dev_pw,
+ size_t dev_pw_len)
{
size_t hash_len;
const u8 *addr[1];
u8 pubkey_hash[WPS_HASH_LEN];
+
+ addr[0] = wpabuf_head(pubkey);
+ hash_len = wpabuf_len(pubkey);
+ sha256_vector(1, addr, &hash_len, pubkey_hash);
+
+ wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
+ wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len);
+ wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+ wpabuf_put_be16(msg, dev_pw_id);
+ wpabuf_put_data(msg, dev_pw, dev_pw_len);
+
+ return 0;
+}
+
+
+int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
+{
u8 dev_password_bin[WPS_OOB_DEVICE_PASSWORD_LEN];
wpa_printf(MSG_DEBUG, "WPS: * OOB Device Password");
- addr[0] = wpabuf_head(wps->dh_pubkey);
- hash_len = wpabuf_len(wps->dh_pubkey);
- sha256_vector(1, addr, &hash_len, pubkey_hash);
-
if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) {
wpa_printf(MSG_ERROR, "WPS: device password id "
"generation error");
@@ -367,19 +390,15 @@
return -1;
}
- wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
- wpabuf_put_be16(msg, WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
- wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
- wpabuf_put_be16(msg, wps->oob_dev_pw_id);
- wpabuf_put_data(msg, dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
-
wpa_snprintf_hex_uppercase(
wpabuf_put(wps->oob_conf.dev_password,
wpabuf_size(wps->oob_conf.dev_password)),
wpabuf_size(wps->oob_conf.dev_password),
dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
- return 0;
+ return wps_build_oob_dev_pw(msg, wps->oob_dev_pw_id, wps->dh_pubkey,
+ dev_password_bin,
+ WPS_OOB_DEVICE_PASSWORD_LEN);
}
#endif /* CONFIG_WPS_OOB */
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index f5ad403..5aa9b00 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
@@ -9,7 +9,8 @@
#include "includes.h"
#include "common.h"
-#include "wps_i.h"
+#include "wps_defs.h"
+#include "wps_attr_parse.h"
#ifndef CONFIG_WPS_STRICT
#define WPS_WORKAROUNDS
@@ -262,12 +263,16 @@
attr->dev_password_id = pos;
break;
case ATTR_OOB_DEVICE_PASSWORD:
- if (len != WPS_OOB_DEVICE_PASSWORD_ATTR_LEN) {
+ if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
+ WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+ len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
+ WPS_OOB_DEVICE_PASSWORD_LEN) {
wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
"Password length %u", len);
return -1;
}
attr->oob_dev_password = pos;
+ attr->oob_dev_password_len = len;
break;
case ATTR_OS_VERSION:
if (len != 4) {
diff --git a/src/wps/wps_attr_parse.h b/src/wps/wps_attr_parse.h
new file mode 100644
index 0000000..332e966
--- /dev/null
+++ b/src/wps/wps_attr_parse.h
@@ -0,0 +1,107 @@
+/*
+ * Wi-Fi Protected Setup - attribute parsing
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_ATTR_PARSE_H
+#define WPS_ATTR_PARSE_H
+
+#include "wps.h"
+
+struct wps_parse_attr {
+ /* fixed length fields */
+ const u8 *version; /* 1 octet */
+ const u8 *version2; /* 1 octet */
+ const u8 *msg_type; /* 1 octet */
+ const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */
+ const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */
+ const u8 *uuid_r; /* WPS_UUID_LEN (16) octets */
+ const u8 *uuid_e; /* WPS_UUID_LEN (16) octets */
+ const u8 *auth_type_flags; /* 2 octets */
+ const u8 *encr_type_flags; /* 2 octets */
+ const u8 *conn_type_flags; /* 1 octet */
+ const u8 *config_methods; /* 2 octets */
+ const u8 *sel_reg_config_methods; /* 2 octets */
+ const u8 *primary_dev_type; /* 8 octets */
+ const u8 *rf_bands; /* 1 octet */
+ const u8 *assoc_state; /* 2 octets */
+ const u8 *config_error; /* 2 octets */
+ const u8 *dev_password_id; /* 2 octets */
+ const u8 *os_version; /* 4 octets */
+ const u8 *wps_state; /* 1 octet */
+ const u8 *authenticator; /* WPS_AUTHENTICATOR_LEN (8) octets */
+ const u8 *r_hash1; /* WPS_HASH_LEN (32) octets */
+ const u8 *r_hash2; /* WPS_HASH_LEN (32) octets */
+ const u8 *e_hash1; /* WPS_HASH_LEN (32) octets */
+ const u8 *e_hash2; /* WPS_HASH_LEN (32) octets */
+ const u8 *r_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
+ const u8 *r_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
+ const u8 *e_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
+ const u8 *e_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
+ const u8 *key_wrap_auth; /* WPS_KWA_LEN (8) octets */
+ const u8 *auth_type; /* 2 octets */
+ const u8 *encr_type; /* 2 octets */
+ const u8 *network_idx; /* 1 octet */
+ const u8 *network_key_idx; /* 1 octet */
+ const u8 *mac_addr; /* ETH_ALEN (6) octets */
+ const u8 *key_prov_auto; /* 1 octet (Bool) */
+ const u8 *dot1x_enabled; /* 1 octet (Bool) */
+ const u8 *selected_registrar; /* 1 octet (Bool) */
+ const u8 *request_type; /* 1 octet */
+ const u8 *response_type; /* 1 octet */
+ const u8 *ap_setup_locked; /* 1 octet */
+ const u8 *settings_delay_time; /* 1 octet */
+ const u8 *network_key_shareable; /* 1 octet (Bool) */
+ const u8 *request_to_enroll; /* 1 octet (Bool) */
+
+ /* variable length fields */
+ const u8 *manufacturer;
+ size_t manufacturer_len;
+ const u8 *model_name;
+ size_t model_name_len;
+ const u8 *model_number;
+ size_t model_number_len;
+ const u8 *serial_number;
+ size_t serial_number_len;
+ const u8 *dev_name;
+ size_t dev_name_len;
+ const u8 *public_key;
+ size_t public_key_len;
+ const u8 *encr_settings;
+ size_t encr_settings_len;
+ const u8 *ssid; /* <= 32 octets */
+ size_t ssid_len;
+ const u8 *network_key; /* <= 64 octets */
+ size_t network_key_len;
+ const u8 *eap_type; /* <= 8 octets */
+ size_t eap_type_len;
+ const u8 *eap_identity; /* <= 64 octets */
+ size_t eap_identity_len;
+ const u8 *authorized_macs; /* <= 30 octets */
+ size_t authorized_macs_len;
+ const u8 *sec_dev_type_list; /* <= 128 octets */
+ size_t sec_dev_type_list_len;
+ const u8 *oob_dev_password; /* 38..54 octets */
+ size_t oob_dev_password_len;
+
+ /* attributes that can occur multiple times */
+#define MAX_CRED_COUNT 10
+ const u8 *cred[MAX_CRED_COUNT];
+ size_t cred_len[MAX_CRED_COUNT];
+ size_t num_cred;
+
+#define MAX_REQ_DEV_TYPE_COUNT 10
+ const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT];
+ size_t num_req_dev_type;
+
+ const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT];
+ size_t vendor_ext_len[MAX_WPS_PARSE_VENDOR_EXT];
+ size_t num_vendor_ext;
+};
+
+int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
+
+#endif /* WPS_ATTR_PARSE_H */
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 2dff4b2..5a8817f 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -1,6 +1,6 @@
/*
* Wi-Fi Protected Setup - common functionality
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -249,6 +249,22 @@
}
+int wps_pin_str_valid(const char *pin)
+{
+ const char *p;
+ size_t len;
+
+ p = pin;
+ while (*p >= '0' && *p <= '9')
+ p++;
+ if (*p != '\0')
+ return 0;
+
+ len = p - pin;
+ return len == 4 || len == 8;
+}
+
+
void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
u16 config_error, u16 error_indication)
{
@@ -308,7 +324,7 @@
#ifdef CONFIG_WPS_OOB
-static struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
{
struct wps_data data;
struct wpabuf *plain;
@@ -335,11 +351,35 @@
}
+struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
+ const struct wpabuf *pubkey,
+ const struct wpabuf *dev_pw)
+{
+ struct wpabuf *data;
+
+ data = wpabuf_alloc(200);
+ if (data == NULL)
+ return NULL;
+
+ if (wps_build_version(data) ||
+ wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
+ wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
+ wps_build_wfa_ext(data, 0, NULL, 0)) {
+ wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
+ "token");
+ wpabuf_free(data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
{
struct wpabuf *data;
- data = wpabuf_alloc(9 + WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
+ data = wpabuf_alloc(200);
if (data == NULL) {
wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
"device password attribute");
@@ -375,6 +415,7 @@
struct oob_conf_data *oob_conf = &wps->oob_conf;
struct wps_parse_attr attr;
const u8 *pos;
+ size_t pw_len;
if (wps_parse_msg(data, &attr) < 0 ||
attr.oob_dev_password == NULL) {
@@ -384,6 +425,7 @@
pos = attr.oob_dev_password;
+ wpabuf_free(oob_conf->pubkey_hash);
oob_conf->pubkey_hash =
wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN);
if (oob_conf->pubkey_hash == NULL) {
@@ -396,39 +438,32 @@
wps->oob_dev_pw_id = WPA_GET_BE16(pos);
pos += sizeof(wps->oob_dev_pw_id);
- oob_conf->dev_password =
- wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
+ pw_len = attr.oob_dev_password_len - WPS_OOB_PUBKEY_HASH_LEN - 2;
+ oob_conf->dev_password = wpabuf_alloc(pw_len * 2 + 1);
if (oob_conf->dev_password == NULL) {
wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
"device password");
return -1;
}
wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password,
- wpabuf_size(oob_conf->dev_password)),
- wpabuf_size(oob_conf->dev_password), pos,
- WPS_OOB_DEVICE_PASSWORD_LEN);
+ pw_len * 2 + 1),
+ pw_len * 2 + 1, pos, pw_len);
return 0;
}
-static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
+int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
{
struct wpabuf msg;
- struct wps_parse_attr attr;
size_t i;
- if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) {
- wpa_printf(MSG_ERROR, "WPS: OOB credential not found");
- return -1;
- }
-
- for (i = 0; i < attr.num_cred; i++) {
+ for (i = 0; i < attr->num_cred; i++) {
struct wps_credential local_cred;
struct wps_parse_attr cattr;
os_memset(&local_cred, 0, sizeof(local_cred));
- wpabuf_set(&msg, attr.cred[i], attr.cred_len[i]);
+ wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]);
if (wps_parse_msg(&msg, &cattr) < 0 ||
wps_process_cred(&cattr, &local_cred)) {
wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
@@ -442,6 +477,19 @@
}
+static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
+{
+ struct wps_parse_attr attr;
+
+ if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) {
+ wpa_printf(MSG_ERROR, "WPS: OOB credential not found");
+ return -1;
+ }
+
+ return wps_oob_use_cred(wps, &attr);
+}
+
+
int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
int registrar)
{
@@ -695,3 +743,53 @@
return msg;
}
+
+
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
+ struct wpabuf **privkey,
+ struct wpabuf **dev_pw)
+{
+ struct wpabuf *priv = NULL, *pub = NULL, *pw, *ret;
+ void *dh_ctx;
+ u16 val;
+
+ pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN);
+ if (pw == NULL)
+ return NULL;
+
+ if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN),
+ WPS_OOB_DEVICE_PASSWORD_LEN) ||
+ random_get_bytes((u8 *) &val, sizeof(val))) {
+ wpabuf_free(pw);
+ return NULL;
+ }
+
+ dh_ctx = dh5_init(&priv, &pub);
+ if (dh_ctx == NULL) {
+ wpabuf_free(pw);
+ return NULL;
+ }
+ dh5_free(dh_ctx);
+
+ *id = 0x10 + val % 0xfff0;
+ wpabuf_free(*pubkey);
+ *pubkey = pub;
+ wpabuf_free(*privkey);
+ *privkey = priv;
+ wpabuf_free(*dev_pw);
+ *dev_pw = pw;
+
+ ret = wps_build_nfc_pw_token(*id, *pubkey, *dev_pw);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index e128a19..2f42603 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -41,7 +41,7 @@
#define WPS_MGMTAUTHKEY_LEN 32
#define WPS_MGMTENCKEY_LEN 16
#define WPS_MGMT_KEY_ID_LEN 16
-#define WPS_OOB_DEVICE_PASSWORD_ATTR_LEN 54
+#define WPS_OOB_DEVICE_PASSWORD_MIN_LEN 16
#define WPS_OOB_DEVICE_PASSWORD_LEN 32
#define WPS_OOB_PUBKEY_HASH_LEN 20
diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c
index 559582d..3c94a43 100644
--- a/src/wps/wps_dev_attr.c
+++ b/src/wps/wps_dev_attr.c
@@ -203,6 +203,20 @@
}
+int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg)
+{
+ if (dev->vendor_ext_m1 != NULL) {
+ wpa_hexdump(MSG_DEBUG, "WPS: * Vendor Extension M1",
+ wpabuf_head_u8(dev->vendor_ext_m1),
+ wpabuf_len(dev->vendor_ext_m1));
+ wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
+ wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext_m1));
+ wpabuf_put_buf(msg, dev->vendor_ext_m1);
+ }
+ return 0;
+}
+
+
int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg)
{
wpa_printf(MSG_DEBUG, "WPS: * RF Bands (%x)", dev->rf_bands);
diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h
index 7ca81ad..200c9c4 100644
--- a/src/wps/wps_dev_attr.h
+++ b/src/wps/wps_dev_attr.h
@@ -17,6 +17,7 @@
int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_primary_dev_type(struct wps_device_data *dev,
struct wpabuf *msg);
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 85d2e95..da0c101 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -163,7 +163,8 @@
wps_build_dev_password_id(msg, wps->dev_pw_id) ||
wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
wps_build_os_version(&wps->wps->dev, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_vendor_ext_m1(&wps->wps->dev, msg)) {
wpabuf_free(msg);
return NULL;
}
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index 0655a3a..95a0dec 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -1,6 +1,6 @@
/*
* Wi-Fi Protected Setup - External Registrar
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -1996,3 +1996,41 @@
return 0;
}
+
+
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid)
+{
+ struct wps_er_ap *ap;
+ struct wpabuf *ret;
+ struct wps_data data;
+
+ if (er == NULL)
+ return NULL;
+
+ ap = wps_er_ap_get(er, NULL, uuid);
+ if (ap == NULL)
+ return NULL;
+ if (ap->ap_settings == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
+ "selected AP");
+ return NULL;
+ }
+
+ ret = wpabuf_alloc(500);
+ if (ret == NULL)
+ return NULL;
+
+ os_memset(&data, 0, sizeof(data));
+ data.wps = er->wps;
+ data.use_cred = ap->ap_settings;
+ if (wps_build_version(ret) ||
+ wps_build_cred(&data, ret) ||
+ wps_build_wfa_ext(ret, 0, NULL, 0)) {
+ wpabuf_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index 1297f65..86ad248 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -1,6 +1,6 @@
/*
* Wi-Fi Protected Setup - internal definitions
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, 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,9 @@
#define WPS_I_H
#include "wps.h"
+#include "wps_attr_parse.h"
+
+struct wps_nfc_pw_token;
/**
* struct wps_data - WPS registration protocol data
@@ -114,100 +117,11 @@
u8 p2p_dev_addr[ETH_ALEN]; /* P2P Device Address of the client or
* 00:00:00:00:00:00 if not a P2p client */
int pbc_in_m1;
+
+ struct wps_nfc_pw_token *nfc_pw_token;
};
-struct wps_parse_attr {
- /* fixed length fields */
- const u8 *version; /* 1 octet */
- const u8 *version2; /* 1 octet */
- const u8 *msg_type; /* 1 octet */
- const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */
- const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */
- const u8 *uuid_r; /* WPS_UUID_LEN (16) octets */
- const u8 *uuid_e; /* WPS_UUID_LEN (16) octets */
- const u8 *auth_type_flags; /* 2 octets */
- const u8 *encr_type_flags; /* 2 octets */
- const u8 *conn_type_flags; /* 1 octet */
- const u8 *config_methods; /* 2 octets */
- const u8 *sel_reg_config_methods; /* 2 octets */
- const u8 *primary_dev_type; /* 8 octets */
- const u8 *rf_bands; /* 1 octet */
- const u8 *assoc_state; /* 2 octets */
- const u8 *config_error; /* 2 octets */
- const u8 *dev_password_id; /* 2 octets */
- const u8 *oob_dev_password; /* WPS_OOB_DEVICE_PASSWORD_ATTR_LEN (54)
- * octets */
- const u8 *os_version; /* 4 octets */
- const u8 *wps_state; /* 1 octet */
- const u8 *authenticator; /* WPS_AUTHENTICATOR_LEN (8) octets */
- const u8 *r_hash1; /* WPS_HASH_LEN (32) octets */
- const u8 *r_hash2; /* WPS_HASH_LEN (32) octets */
- const u8 *e_hash1; /* WPS_HASH_LEN (32) octets */
- const u8 *e_hash2; /* WPS_HASH_LEN (32) octets */
- const u8 *r_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
- const u8 *r_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
- const u8 *e_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
- const u8 *e_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
- const u8 *key_wrap_auth; /* WPS_KWA_LEN (8) octets */
- const u8 *auth_type; /* 2 octets */
- const u8 *encr_type; /* 2 octets */
- const u8 *network_idx; /* 1 octet */
- const u8 *network_key_idx; /* 1 octet */
- const u8 *mac_addr; /* ETH_ALEN (6) octets */
- const u8 *key_prov_auto; /* 1 octet (Bool) */
- const u8 *dot1x_enabled; /* 1 octet (Bool) */
- const u8 *selected_registrar; /* 1 octet (Bool) */
- const u8 *request_type; /* 1 octet */
- const u8 *response_type; /* 1 octet */
- const u8 *ap_setup_locked; /* 1 octet */
- const u8 *settings_delay_time; /* 1 octet */
- const u8 *network_key_shareable; /* 1 octet (Bool) */
- const u8 *request_to_enroll; /* 1 octet (Bool) */
-
- /* variable length fields */
- const u8 *manufacturer;
- size_t manufacturer_len;
- const u8 *model_name;
- size_t model_name_len;
- const u8 *model_number;
- size_t model_number_len;
- const u8 *serial_number;
- size_t serial_number_len;
- const u8 *dev_name;
- size_t dev_name_len;
- const u8 *public_key;
- size_t public_key_len;
- const u8 *encr_settings;
- size_t encr_settings_len;
- const u8 *ssid; /* <= 32 octets */
- size_t ssid_len;
- const u8 *network_key; /* <= 64 octets */
- size_t network_key_len;
- const u8 *eap_type; /* <= 8 octets */
- size_t eap_type_len;
- const u8 *eap_identity; /* <= 64 octets */
- size_t eap_identity_len;
- const u8 *authorized_macs; /* <= 30 octets */
- size_t authorized_macs_len;
- const u8 *sec_dev_type_list; /* <= 128 octets */
- size_t sec_dev_type_list_len;
-
- /* attributes that can occur multiple times */
-#define MAX_CRED_COUNT 10
- const u8 *cred[MAX_CRED_COUNT];
- size_t cred_len[MAX_CRED_COUNT];
- size_t num_cred;
-
-#define MAX_REQ_DEV_TYPE_COUNT 10
- const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT];
- size_t num_req_dev_type;
-
- const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT];
- size_t vendor_ext_len[MAX_WPS_PARSE_VENDOR_EXT];
- size_t num_vendor_ext;
-};
-
/* wps_common.c */
void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
const char *label, u8 *res, size_t res_len);
@@ -230,9 +144,6 @@
struct wpabuf * wps_build_wsc_ack(struct wps_data *wps);
struct wpabuf * wps_build_wsc_nack(struct wps_data *wps);
-/* wps_attr_parse.c */
-int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
-
/* wps_attr_build.c */
int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg);
int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type);
@@ -255,6 +166,9 @@
int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg);
int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg);
int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
+ const struct wpabuf *pubkey, const u8 *dev_pw,
+ size_t dev_pw_len);
int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps);
struct wpabuf * wps_ie_encapsulate(struct wpabuf *data);
@@ -288,9 +202,7 @@
const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count);
int wps_registrar_pbc_overlap(struct wps_registrar *reg,
const u8 *addr, const u8 *uuid_e);
-
-/* ndef.c */
-struct wpabuf * ndef_parse_wifi(struct wpabuf *buf);
-struct wpabuf * ndef_build_wifi(struct wpabuf *buf);
+void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
+ struct wps_nfc_pw_token *token);
#endif /* WPS_I_H */
diff --git a/src/wps/wps_nfc.c b/src/wps/wps_nfc.c
index ff12000..6804350 100644
--- a/src/wps/wps_nfc.c
+++ b/src/wps/wps_nfc.c
@@ -1,15 +1,9 @@
/*
* NFC routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp>
+ * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com>
*
- * 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 "includes.h"
diff --git a/src/wps/wps_nfc_pn531.c b/src/wps/wps_nfc_pn531.c
index 7e05e4d..c2bf457 100644
--- a/src/wps/wps_nfc_pn531.c
+++ b/src/wps/wps_nfc_pn531.c
@@ -1,15 +1,9 @@
/*
* NFC PN531 routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp>
+ * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com>
*
- * 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 "includes.h"
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 5ed7ea4..44bb006 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -1,6 +1,6 @@
/*
* Wi-Fi Protected Setup - Registrar
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -26,6 +26,53 @@
#define WPS_WORKAROUNDS
#endif /* CONFIG_WPS_STRICT */
+#ifdef CONFIG_WPS_NFC
+
+struct wps_nfc_pw_token {
+ struct dl_list list;
+ u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
+ u16 pw_id;
+ u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
+ size_t dev_pw_len;
+};
+
+
+static void wps_remove_nfc_pw_token(struct wps_nfc_pw_token *token)
+{
+ dl_list_del(&token->list);
+ os_free(token);
+}
+
+
+static void wps_free_nfc_pw_tokens(struct dl_list *tokens, u16 pw_id)
+{
+ struct wps_nfc_pw_token *token, *prev;
+ dl_list_for_each_safe(token, prev, tokens, struct wps_nfc_pw_token,
+ list) {
+ if (pw_id == 0 || pw_id == token->pw_id)
+ wps_remove_nfc_pw_token(token);
+ }
+}
+
+
+static struct wps_nfc_pw_token * wps_get_nfc_pw_token(struct dl_list *tokens,
+ u16 pw_id)
+{
+ struct wps_nfc_pw_token *token;
+ dl_list_for_each(token, tokens, struct wps_nfc_pw_token, list) {
+ if (pw_id == token->pw_id)
+ return token;
+ }
+ return NULL;
+}
+
+#else /* CONFIG_WPS_NFC */
+
+#define wps_free_nfc_pw_tokens(t, p) do { } while (0)
+
+#endif /* CONFIG_WPS_NFC */
+
+
struct wps_uuid_pin {
struct dl_list list;
u8 uuid[WPS_UUID_LEN];
@@ -102,7 +149,8 @@
void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
const struct wps_device_data *dev);
void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
- const u8 *uuid_e);
+ const u8 *uuid_e, const u8 *dev_pw,
+ size_t dev_pw_len);
void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,
u16 sel_reg_config_methods);
void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,
@@ -112,6 +160,7 @@
void *cb_ctx;
struct dl_list pins;
+ struct dl_list nfc_pw_tokens;
struct wps_pbc_session *pbc_sessions;
int skip_cred_build;
@@ -484,12 +533,16 @@
{
*methods |= WPS_CONFIG_PUSHBUTTON;
#ifdef CONFIG_WPS2
- if (conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON)
+ if ((conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON) ==
+ WPS_CONFIG_VIRT_PUSHBUTTON)
*methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
- if (conf_methods & WPS_CONFIG_PHY_PUSHBUTTON)
+ if ((conf_methods & WPS_CONFIG_PHY_PUSHBUTTON) ==
+ WPS_CONFIG_PHY_PUSHBUTTON)
*methods |= WPS_CONFIG_PHY_PUSHBUTTON;
- if (!(*methods & (WPS_CONFIG_VIRT_PUSHBUTTON |
- WPS_CONFIG_PHY_PUSHBUTTON))) {
+ if ((*methods & WPS_CONFIG_VIRT_PUSHBUTTON) !=
+ WPS_CONFIG_VIRT_PUSHBUTTON &&
+ (*methods & WPS_CONFIG_PHY_PUSHBUTTON) !=
+ WPS_CONFIG_PHY_PUSHBUTTON) {
/*
* Required to include virtual/physical flag, but we were not
* configured with push button type, so have to default to one
@@ -591,6 +644,7 @@
return NULL;
dl_list_init(®->pins);
+ dl_list_init(®->nfc_pw_tokens);
reg->wps = wps;
reg->new_psk_cb = cfg->new_psk_cb;
reg->set_ie_cb = cfg->set_ie_cb;
@@ -634,6 +688,7 @@
eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
wps_free_pins(®->pins);
+ wps_free_nfc_pw_tokens(®->nfc_pw_tokens, 0);
wps_free_pbc_sessions(reg->pbc_sessions);
wpabuf_free(reg->extra_cred);
wps_free_devices(reg->devices);
@@ -740,14 +795,22 @@
/**
* wps_registrar_invalidate_wildcard_pin - Invalidate a wildcard PIN
* @reg: Registrar data from wps_registrar_init()
+ * @dev_pw: PIN to search for or %NULL to match any
+ * @dev_pw_len: Length of dev_pw in octets
* Returns: 0 on success, -1 if not wildcard PIN is enabled
*/
-static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg)
+static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg,
+ const u8 *dev_pw,
+ size_t dev_pw_len)
{
struct wps_uuid_pin *pin, *prev;
dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list)
{
+ if (dev_pw && pin->pin &&
+ (dev_pw_len != pin->pin_len ||
+ os_memcmp(dev_pw, pin->pin, dev_pw_len) != 0))
+ continue; /* different PIN */
if (pin->wildcard_uuid) {
wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
pin->uuid, WPS_UUID_LEN);
@@ -945,7 +1008,8 @@
}
-void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e)
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,
+ const u8 *dev_pw, size_t dev_pw_len)
{
if (registrar->pbc) {
wps_registrar_remove_pbc_session(registrar,
@@ -954,6 +1018,13 @@
} else {
wps_registrar_pin_completed(registrar);
}
+
+ if (dev_pw &&
+ wps_registrar_invalidate_wildcard_pin(registrar, dev_pw,
+ dev_pw_len) == 0) {
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Invalidated wildcard PIN",
+ dev_pw, dev_pw_len);
+ }
}
@@ -968,7 +1039,7 @@
/* PIN Method */
wpa_printf(MSG_DEBUG, "WPS: PIN is set - cancelling it");
wps_registrar_pin_completed(reg);
- wps_registrar_invalidate_wildcard_pin(reg);
+ wps_registrar_invalidate_wildcard_pin(reg, NULL, 0);
return 1;
}
return 0;
@@ -1071,12 +1142,13 @@
static void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr,
- const u8 *uuid_e)
+ const u8 *uuid_e, const u8 *dev_pw,
+ size_t dev_pw_len)
{
if (reg->reg_success_cb == NULL)
return;
- reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e);
+ reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e, dev_pw, dev_pw_len);
}
@@ -1238,6 +1310,13 @@
wpa_printf(MSG_DEBUG, "WPS: Use default PIN for PBC");
pin = (const u8 *) "00000000";
pin_len = 8;
+#ifdef CONFIG_WPS_NFC
+ } else if (wps->nfc_pw_token) {
+ wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from NFC "
+ "Password Token");
+ pin = wps->nfc_pw_token->dev_pw;
+ pin_len = wps->nfc_pw_token->dev_pw_len;
+#endif /* CONFIG_WPS_NFC */
} else {
pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
&pin_len);
@@ -2424,8 +2503,34 @@
return WPS_CONTINUE;
}
+#ifdef CONFIG_WPS_NFC
+ if (wps->dev_pw_id >= 0x10) {
+ struct wps_nfc_pw_token *token;
+ const u8 *addr[1];
+ u8 hash[WPS_HASH_LEN];
+
+ token = wps_get_nfc_pw_token(
+ &wps->wps->registrar->nfc_pw_tokens, wps->dev_pw_id);
+ if (token) {
+ wpa_printf(MSG_DEBUG, "WPS: Found matching NFC "
+ "Password Token");
+ dl_list_del(&token->list);
+ wps->nfc_pw_token = token;
+
+ addr[0] = attr->public_key;
+ sha256_vector(1, addr, &attr->public_key_len, hash);
+ if (os_memcmp(hash, wps->nfc_pw_token->pubkey_hash,
+ WPS_OOB_PUBKEY_HASH_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "WPS: Public Key hash "
+ "mismatch");
+ return WPS_FAILURE;
+ }
+ }
+ }
+#endif /* CONFIG_WPS_NFC */
+
#ifdef CONFIG_WPS_OOB
- if (wps->dev_pw_id >= 0x10 &&
+ if (wps->dev_pw_id >= 0x10 && wps->nfc_pw_token == NULL &&
wps->dev_pw_id != wps->wps->oob_dev_pw_id) {
wpa_printf(MSG_DEBUG, "WPS: OOB Device Password ID "
"%d mismatch", wps->dev_pw_id);
@@ -3055,7 +3160,8 @@
wps->new_psk = NULL;
}
- wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e);
+ wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e,
+ wps->dev_password, wps->dev_password_len);
if (wps->pbc) {
wps_registrar_remove_pbc_session(wps->wps->registrar,
@@ -3348,3 +3454,84 @@
return -1;
}
+
+
+#ifdef CONFIG_WPS_NFC
+
+int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
+ const u8 *pubkey_hash, u16 pw_id,
+ const u8 *dev_pw, size_t dev_pw_len)
+{
+ struct wps_nfc_pw_token *token;
+
+ if (dev_pw_len > WPS_OOB_DEVICE_PASSWORD_LEN)
+ return -1;
+
+ wps_free_nfc_pw_tokens(®->nfc_pw_tokens, pw_id);
+
+ token = os_zalloc(sizeof(*token));
+ if (token == NULL)
+ return -1;
+
+ os_memcpy(token->pubkey_hash, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+ token->pw_id = pw_id;
+ os_memcpy(token->dev_pw, dev_pw, dev_pw_len);
+ token->dev_pw_len = dev_pw_len;
+
+ dl_list_add(®->nfc_pw_tokens, &token->list);
+
+ reg->selected_registrar = 1;
+ reg->pbc = 0;
+ wps_registrar_add_authorized_mac(reg,
+ (u8 *) "\xff\xff\xff\xff\xff\xff");
+ wps_registrar_selected_registrar_changed(reg);
+ eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
+ eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
+ wps_registrar_set_selected_timeout,
+ reg, NULL);
+
+ return 0;
+}
+
+
+int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
+ const u8 *oob_dev_pw,
+ size_t oob_dev_pw_len)
+{
+ const u8 *pos, *hash, *dev_pw;
+ u16 id;
+ size_t dev_pw_len;
+
+ if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
+ WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+ oob_dev_pw_len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
+ WPS_OOB_DEVICE_PASSWORD_LEN)
+ return -1;
+
+ hash = oob_dev_pw;
+ pos = oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN;
+ id = WPA_GET_BE16(pos);
+ dev_pw = pos + 2;
+ dev_pw_len = oob_dev_pw + oob_dev_pw_len - dev_pw;
+
+ wpa_printf(MSG_DEBUG, "WPS: Add NFC Password Token for Password ID %u",
+ id);
+
+ wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash",
+ hash, WPS_OOB_PUBKEY_HASH_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Device Password", dev_pw, dev_pw_len);
+
+ return wps_registrar_add_nfc_pw_token(reg, hash, id, dev_pw,
+ dev_pw_len);
+}
+
+
+void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
+ struct wps_nfc_pw_token *token)
+{
+ wps_registrar_remove_authorized_mac(reg,
+ (u8 *) "\xff\xff\xff\xff\xff\xff");
+ wps_registrar_selected_registrar_changed(reg);
+}
+
+#endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_ufd.c b/src/wps/wps_ufd.c
index 61f6553..f83bdf4 100644
--- a/src/wps/wps_ufd.c
+++ b/src/wps/wps_ufd.c
@@ -1,15 +1,9 @@
/*
* UFD routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp>
+ * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com>
*
- * 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 "includes.h"
@@ -165,8 +159,10 @@
}
data = os_zalloc(sizeof(*data));
- if (data == NULL)
+ if (data == NULL) {
+ close(ufd_fd);
return NULL;
+ }
data->ufd_fd = ufd_fd;
return data;
}
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 766cac4..09a46a2 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -305,15 +305,15 @@
int alloc_len;
char *scratch_mem = NULL;
char *mem;
- char *domain_and_port;
+ char *host;
char *delim;
char *path;
- char *domain;
int port = 80; /* port to send to (default is port 80) */
struct addrinfo hints;
struct addrinfo *result = NULL;
struct addrinfo *rp;
int rerr;
+ size_t host_len, path_len;
/* url MUST begin with http: */
if (url_len < 7 || os_strncasecmp(url, "http://", 7))
@@ -321,30 +321,24 @@
url += 7;
url_len -= 7;
- /* allocate memory for the extra stuff we need */
- alloc_len = 2 * (url_len + 1);
- scratch_mem = os_zalloc(alloc_len);
+ /* Make a copy of the string to allow modification during parsing */
+ scratch_mem = os_malloc(url_len + 1);
if (scratch_mem == NULL)
goto fail;
- mem = scratch_mem;
- os_strncpy(mem, url, url_len);
- wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", mem);
- domain_and_port = mem;
- mem += 1 + os_strlen(mem);
- delim = os_strchr(domain_and_port, '/');
+ os_memcpy(scratch_mem, url, url_len);
+ scratch_mem[url_len] = '\0';
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", scratch_mem);
+ host = scratch_mem;
+ path = os_strchr(host, '/');
+ if (path)
+ *path++ = '\0'; /* null terminate host */
+
+ /* Process and remove optional port component */
+ delim = os_strchr(host, ':');
if (delim) {
- *delim++ = 0; /* null terminate domain and port */
- path = delim;
- } else {
- path = domain_and_port + os_strlen(domain_and_port);
- }
- domain = mem;
- strcpy(domain, domain_and_port);
- delim = os_strchr(domain, ':');
- if (delim) {
- *delim++ = 0; /* null terminate domain */
- if (isdigit(*delim))
- port = atol(delim);
+ *delim = '\0'; /* null terminate host name for now */
+ if (isdigit(delim[1]))
+ port = atol(delim + 1);
}
/*
@@ -367,13 +361,21 @@
hints.ai_flags = 0;
#endif
hints.ai_protocol = 0; /* Any protocol? */
- rerr = getaddrinfo(domain, NULL /* fill in port ourselves */,
+ rerr = getaddrinfo(host, NULL /* fill in port ourselves */,
&hints, &result);
if (rerr) {
wpa_printf(MSG_INFO, "WPS UPnP: Resolve error %d (%s) on: %s",
- rerr, gai_strerror(rerr), domain);
+ rerr, gai_strerror(rerr), host);
goto fail;
}
+
+ if (delim)
+ *delim = ':'; /* Restore port */
+
+ host_len = os_strlen(host);
+ path_len = path ? os_strlen(path) : 0;
+ alloc_len = host_len + 1 + 1 + path_len + 1;
+
for (rp = result; rp; rp = rp->ai_next) {
struct subscr_addr *a;
@@ -386,16 +388,16 @@
a = os_zalloc(sizeof(*a) + alloc_len);
if (a == NULL)
- continue;
- mem = (void *) (a + 1);
+ break;
+ mem = (char *) (a + 1);
a->domain_and_port = mem;
- strcpy(mem, domain_and_port);
- mem += 1 + strlen(mem);
+ os_memcpy(mem, host, host_len);
+ mem += host_len + 1;
a->path = mem;
- if (path[0] != '/')
+ if (path == NULL || path[0] != '/')
*mem++ = '/';
- strcpy(mem, path);
- mem += 1 + os_strlen(mem);
+ if (path)
+ os_memcpy(mem, path, path_len);
os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr));
a->saddr.sin_port = htons(port);
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index 4c4aebf..17a8207 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -866,20 +866,24 @@
return -1;
#if 0 /* maybe ok if we sometimes block on writes */
- if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
+ if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) {
+ close(sd);
return -1;
+ }
#endif
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF,
&ip_addr, sizeof(ip_addr))) {
wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_IF) %x: "
"%d (%s)", ip_addr, errno, strerror(errno));
+ close(sd);
return -1;
}
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
&ttl, sizeof(ttl))) {
wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_TTL): "
"%d (%s)", errno, strerror(errno));
+ close(sd);
return -1;
}
@@ -898,6 +902,7 @@
"WPS UPnP: setsockopt "
"IP_ADD_MEMBERSHIP errno %d (%s)",
errno, strerror(errno));
+ close(sd);
return -1;
}
}
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index c6cf80b..231cd57 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1310,6 +1310,23 @@
OBJS += bgscan.c
endif
+ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+L_CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL
+OBJS += autoscan_exponential.c
+NEED_AUTOSCAN=y
+endif
+
+ifdef CONFIG_AUTOSCAN_PERIODIC
+CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+OBJS += autoscan_periodic.c
+NEED_AUTOSCAN=y
+endif
+
+ifdef NEED_AUTOSCAN
+L_CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.c
+endif
+
ifdef NEED_GAS
OBJS += ../src/common/gas.c
OBJS += gas_query.c
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index 06119c6..650b8a0 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,179 @@
ChangeLog for wpa_supplicant
+2012-05-10 - v1.0
+ * bsd: Add support for setting HT values in IFM_MMASK.
+ * Delay STA entry removal until Deauth/Disassoc TX status in AP mode.
+ This allows the driver to use PS buffering of Deauthentication and
+ Disassociation frames when the STA is in power save sleep. Only
+ available with drivers that provide TX status events for Deauth/
+ Disassoc frames (nl80211).
+ * Drop oldest unknown BSS table entries first. This makes it less
+ likely to hit connection issues in environments with huge number
+ of visible APs.
+ * Add systemd support.
+ * Add support for setting the syslog facility from the config file
+ at build time.
+ * atheros: Add support for IEEE 802.11w configuration.
+ * AP mode: Allow enable HT20 if driver supports it, by setting the
+ config parameter ieee80211n.
+ * Allow AP mode to disconnect STAs based on low ACK condition (when
+ the data connection is not working properly, e.g., due to the STA
+ going outside the range of the AP). Disabled by default, enable by
+ config option disassoc_low_ack.
+ * nl80211:
+ - Support GTK rekey offload.
+ - Support PMKSA candidate events. This adds support for RSN
+ pre-authentication with nl80211 interface and drivers that handle
+ roaming internally.
+ * dbus:
+ - Add a DBus signal for EAP SM requests, emitted on the Interface
+ object.
+ - Export max scan ssids supported by the driver as MaxScanSSID.
+ - Add signal Certification for information about server certification.
+ - Add BSSExpireAge and BSSExpireCount interface properties and
+ support set/get, which allows for setting BSS cache expiration age
+ and expiration scan count.
+ - Add ConfigFile to AddInterface properties.
+ - Add Interface.Country property and support to get/set the value.
+ - Add DBus property CurrentAuthMode.
+ - P2P DBus API added.
+ - Emit property changed events (for property BSSs) when adding/
+ removing BSSs.
+ - Treat '' in SSIDs of Interface.Scan as a request for broadcast
+ scan, instead of ignoring it.
+ - Add DBus getter/setter for FastReauth.
+ - Raise PropertiesChanged on org.freedesktop.DBus.Properties.
+ * wpa_cli:
+ - Send AP-STA-DISCONNECTED event when an AP disconnects a station
+ due to inactivity.
+ - Make second argument to set command optional. This can be used to
+ indicate a zero length value.
+ - Add signal_poll command.
+ - Add bss_expire_age and bss_expire_count commands to set/get BSS
+ cache expiration age and expiration scan count.
+ - Add ability to set scan interval (the time in seconds wpa_s waits
+ before requesting a new scan after failing to find a suitable
+ network in scan results) using scan_interval command.
+ - Add event CTRL-EVENT-ASSOC-REJECT for association rejected.
+ - Add command get version, that returns wpa_supplicant version string.
+ - Add command sta_autoconnect for disabling automatic reconnection
+ on receiving disconnection event.
+ - Setting bssid parameter to an empty string "" or any can now be
+ used to clear the bssid_set flag in a network block, i.e., to remove
+ bssid filtering.
+ - Add tdls_testing command to add a special testing feature for
+ changing TDLS behavior. Build param CONFIG_TDLS_TESTING must be
+ enabled as well.
+ - For interworking, add wpa_cli commands interworking_select,
+ interworking_connect, anqp_get, fetch_anqp, and stop_fetch_anqp.
+ - Many P2P commands were added. See README-P2P.
+ - Many WPS/WPS ER commands - see WPS/WPS ER sections for details.
+ - Allow set command to change global config parameters.
+ - Add log_level command, which can be used to display the current
+ debugging level and to change the log level during run time.
+ - Add note command, which can be used to insert notes to the debug
+ log.
+ - Add internal line edit implementation. CONFIG_WPA_CLI_EDIT=y
+ can now be used to build wpa_cli with internal implementation of
+ line editing and history support. This can be used as a replacement
+ for CONFIG_READLINE=y.
+ * AP mode: Add max_num_sta config option, which can be used to limit
+ the number of stations allowed to connect to the AP.
+ * Add WPA_IGNORE_CONFIG_ERRORS build option to continue in case of bad
+ config file.
+ * wext: Increase scan timeout from 5 to 10 seconds.
+ * Add blacklist command, allowing an external program to
+ manage the BSS blacklist and display its current contents.
+ * WPS:
+ - Add wpa_cli wps_pin get command for generating random PINs. This can
+ be used in a UI to generate a PIN without starting WPS (or P2P)
+ operation.
+ - Set RF bands based on driver capabilities, instead of hardcoding
+ them.
+ - Add mechanism for indicating non-standard WPS errors.
+ - Add CONFIG_WPS_REG_DISABLE_OPEN=y option to disable open networks
+ by default.
+ - Add wps_ap_pin cli command for wpa_supplicant AP mode.
+ - Add wps_check_pin cli command for processing PIN from user input.
+ UIs can use this command to process a PIN entered by a user and to
+ validate the checksum digit (if present).
+ - Cancel WPS operation on PBC session overlap detection.
+ - New wps_cancel command in wpa_cli will cancel a pending WPS
+ operation.
+ - wpa_cli action: Add WPS_EVENT_SUCCESS and WPS_EVENT_FAIL handlers.
+ - Trigger WPS config update on Manufacturer, Model Name, Model
+ Number, and Serial Number changes.
+ - Fragment size is now configurable for EAP-WSC peer. Use
+ wpa_cli set wps_fragment_size <val>.
+ - Disable AP PIN after 10 consecutive failures. Slow down attacks on
+ failures up to 10.
+ - Allow AP to start in Enrollee mode without AP PIN for probing, to
+ be compatible with Windows 7.
+ - Add Config Error into WPS-FAIL events to provide more info to the
+ user on how to resolve the issue.
+ - Label and Display config methods are not allowed to be enabled
+ at the same time, since it is unclear which PIN to use if both
+ methods are advertised.
+ - When controlling multiple interfaces:
+ - apply WPS commands to all interfaces configured to use WPS
+ - apply WPS config changes to all interfaces that use WPS
+ - when an attack is detected on any interface, disable AP PIN on
+ all interfaces
+ * WPS ER:
+ - Add special AP Setup Locked mode to allow read only ER.
+ ap_setup_locked=2 can now be used to enable a special mode where
+ WPS ER can learn the current AP settings, but cannot change them.
+ - Show SetSelectedRegistrar events as ctrl_iface events
+ - Add wps_er_set_config to enroll a network based on a local
+ network configuration block instead of having to (re-)learn the
+ current AP settings with wps_er_learn.
+ - Allow AP filtering based on IP address, add ctrl_iface event for
+ learned AP settings, add wps_er_config command to configure an AP.
+ * WPS 2.0: Add support for WPS 2.0 (CONFIG_WPS2)
+ - Add build option CONFIG_WPS_EXTENSIBILITY_TESTING to enable tool
+ for testing protocol extensibility.
+ - Add build option CONFIG_WPS_STRICT to allow disabling of WPS
+ workarounds.
+ - Add support for AuthorizedMACs attribute.
+ * TDLS:
+ - Propogate TDLS related nl80211 capability flags from kernel and
+ add them as driver capability flags. If the driver doesn't support
+ capabilities, assume TDLS is supported internally. When TDLS is
+ explicitly not supported, disable all user facing TDLS operations.
+ - Allow TDLS to be disabled at runtime (mostly for testing).
+ Use set tdls_disabled.
+ - Honor AP TDLS settings that prohibit/allow TDLS.
+ - Add a special testing feature for changing TDLS behavior. Use
+ CONFIG_TDLS_TESTING build param to enable. Configure at runtime
+ with tdls_testing cli command.
+ - Add support for TDLS 802.11z.
+ * wlantest: Add a tool wlantest for IEEE802.11 protocol testing.
+ wlantest can be used to capture frames from a monitor interface
+ for realtime capturing or from pcap files for offline analysis.
+ * Interworking: Support added for 802.11u. Enable in .config with
+ CONFIG_INTERWORKING. See wpa_supplicant.conf for config parameters
+ for interworking. wpa_cli commands added to support this are
+ interworking_select, interworking_connect, anqp_get, fetch_anqp,
+ and stop_fetch_anqp.
+ * Android: Add build and runtime support for Android wpa_supplicant.
+ * bgscan learn: Add new bgscan that learns BSS information based on
+ previous scans, and uses that information to dynamically generate
+ the list of channels for background scans.
+ * Add a new debug message level for excessive information. Use
+ -ddd to enable.
+ * TLS: Add support for tls_disable_time_checks=1 in client mode.
+ * Internal TLS:
+ - Add support for TLS v1.1 (RFC 4346). Enable with build parameter
+ CONFIG_TLSV11.
+ - Add domainComponent parser for X.509 names.
+ * Linux: Add RFKill support by adding an interface state "disabled".
+ * Reorder some IEs to get closer to IEEE 802.11 standard. Move
+ WMM into end of Beacon, Probe Resp and (Re)Assoc Resp frames.
+ Move HT IEs to be later in (Re)Assoc Resp.
+ * Solaris: Add support for wired 802.1X client.
+ * Wi-Fi Direct support. See README-P2P for more information.
+ * Many bugfixes.
+
2010-04-18 - v0.7.2
* nl80211: fixed number of issues with roaming
* avoid unnecessary roaming if multiple APs with similar signal
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 03241c5..6756e54 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -227,6 +227,12 @@
endif
endif
+ifdef CONFIG_HS20
+OBJS += hs20_supplicant.o
+CFLAGS += -DCONFIG_HS20
+CONFIG_INTERWORKING=y
+endif
+
ifdef CONFIG_INTERWORKING
OBJS += interworking.o
CFLAGS += -DCONFIG_INTERWORKING
@@ -716,6 +722,10 @@
CFLAGS += -DCONFIG_IEEE80211N
endif
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+endif
+
ifdef NEED_AP_MLME
OBJS += ../src/ap/wmm.o
OBJS += ../src/ap/ap_list.o
@@ -728,6 +738,9 @@
OBJS += ../src/ap/wps_hostapd.o
OBJS += ../src/eap_server/eap_server_wsc.o
endif
+ifdef CONFIG_INTERWORKING
+OBJS += ../src/ap/gas_serv.o
+endif
endif
ifdef NEED_RSN_AUTHENTICATOR
@@ -1270,6 +1283,10 @@
endif
endif
+ifdef CONFIG_DEBUG_LINUX_TRACING
+CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
ifdef CONFIG_DEBUG_FILE
CFLAGS += -DCONFIG_DEBUG_FILE
endif
@@ -1304,6 +1321,23 @@
OBJS += bgscan.o
endif
+ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL
+OBJS += autoscan_exponential.o
+NEED_AUTOSCAN=y
+endif
+
+ifdef CONFIG_AUTOSCAN_PERIODIC
+CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+OBJS += autoscan_periodic.o
+NEED_AUTOSCAN=y
+endif
+
+ifdef NEED_AUTOSCAN
+CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.o
+endif
+
ifdef NEED_GAS
OBJS += ../src/common/gas.o
OBJS += gas_query.o
@@ -1332,6 +1366,10 @@
OBJS_t += ../src/utils/ip_addr.o
endif
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
+
+OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o
+OBJS_nfc += $(OBJS_d) ../src/drivers/drivers.o
+
OBJS += $(CONFIG_MAIN).o
ifdef CONFIG_PRIVSEP
@@ -1440,6 +1478,10 @@
$(Q)$(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS)
@$(E) " LD " $@
+nfc_pw_token: $(OBJS_nfc)
+ $(Q)$(LDO) $(LDFLAGS) -o nfc_pw_token $(OBJS_nfc) $(LIBS)
+ @$(E) " LD " $@
+
win_if_list: win_if_list.c
$(Q)$(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
@$(E) " LD " $@
@@ -1522,5 +1564,6 @@
$(MAKE) -C dbus clean
rm -f core *~ *.o *.d eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
rm -f wpa_priv
+ rm -f nfc_pw_token
-include $(OBJS:%.o=%.d)
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 9ee82a2..a06e5c1 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -425,7 +425,7 @@
-K = include keys (passwords, etc.) in debug output
-t = include timestamp in debug messages
-h = show this help text
- -L = show license (GPL and BSD)
+ -L = show license (BSD)
-p = driver parameters
-P = PID file
-q = decrease debugging verbosity (-qq even less)
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index db6e4ae..bb4c2ad 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -101,7 +101,7 @@
Group Formation
-p2p_prov_disc <peer device address> <display|keypad|pbc> [join]
+p2p_prov_disc <peer device address> <display|keypad|pbc> [join|auto]
Send P2P provision discovery request to the specified peer. The
parameters for this command are the P2P device address of the peer and
@@ -112,10 +112,14 @@
The optional "join" parameter can be used to indicate that this command
is requesting an already running GO to prepare for a new client. This is
-mainly used with "display" to request it to display a PIN.
+mainly used with "display" to request it to display a PIN. The "auto"
+parameter can be used to request wpa_supplicant to automatically figure
+out whether the peer device is operating as a GO and if so, use
+join-a-group style PD instead of GO Negotiation style PD.
p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
- [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>]
+ [persistent|persistent=<network id>] [join|auth]
+ [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
Start P2P group formation with a discovered P2P peer. This includes
optional group owner negotiation, group interface setup, provisioning,
@@ -128,7 +132,12 @@
used (e.g., 12345670). [display|keypad] is used with PIN method
to specify which PIN is used (display=dynamically generated random PIN
from local display, keypad=PIN entered from peer display). "persistent"
-parameter can be used to request a persistent group to be formed.
+parameter can be used to request a persistent group to be formed. The
+"persistent=<network id>" alternative can be used to pre-populate
+SSID/passphrase configuration based on a previously used persistent
+group where this device was the GO. The previously used parameters will
+then be used if the local end becomes the GO in GO Negotiation (which
+can be forced with go_intent=15).
"join" indicates that this is a command to join an existing group as a
client. It skips the GO Negotiation part. This will send a Provision
@@ -146,6 +155,11 @@
"freq" can be used to set a forced operating channel (e.g., freq=2412
to select 2.4 GHz channel 1).
+"provdisc" can be used to request a Provision Discovery exchange to be
+used prior to starting GO Negotiation as a workaround with some deployed
+P2P implementations that require this to allow the user to accept the
+connection.
+
p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
Set up a P2P group owner manually (i.e., without group owner
@@ -322,7 +336,7 @@
Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
persistent group (e.g., persistent=4). If the peer device is the GO of
-the persisten group, the peer parameter is not needed. Otherwise it is
+the persistent group, the peer parameter is not needed. Otherwise it is
used to specify which device to invite. go_dev_addr parameter can be
used to override the GO device address for Invitation Request should
it be not known for some reason (this should not be needed in most
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index bf75cb4..692d5f5 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -67,6 +67,10 @@
CONFIG_WPS_ER=y
+Following parameter can be used to enable support for NFC config method:
+
+CONFIG_WPS_NFC=y
+
WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for
the device. This is configured in the runtime configuration for
@@ -303,3 +307,41 @@
- WPS ER learned AP settings
WPS-ER-AP-SETTINGS uuid=fd91b4ec-e3fa-5891-a57d-8c59efeed1d2 ssid=test-wps auth_type=0x0020 encr_type=0x0008 key=12345678
+
+
+WPS with NFC
+------------
+
+WPS can be used with NFC-based configuration method. An NFC tag
+containing a password token from the Enrollee can be used to
+authenticate the connection instead of the PIN. In addition, an NFC tag
+with a configuration token can be used to transfer AP settings without
+going through the WPS protocol.
+
+When the station acts as an Enrollee, a local NFC tag with a password
+token can be used by touching the NFC interface of a Registrar.
+
+"wps_nfc [BSSID]" command starts WPS protocol run with the local end as
+the Enrollee using the NFC password token that is either pre-configured
+in the configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey,
+wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
+"wps_nfc_token <WPS|NDEF>" command. The included nfc_pw_token tool
+(build with "make nfc_pw_token") can be used to generate NFC password
+tokens during manufacturing (each station needs to have its own random
+keys).
+
+If the station includes NFC interface and reads an NFC tag with a MIME
+media type "application/vnd.wfa.wsc", the NDEF message payload (with or
+without NDEF encapsulation) can be delivered to wpa_supplicant using the
+following wpa_cli command:
+
+wps_nfc_tag_read <hexdump of payload>
+
+If the NFC tag contains a configuration token, the network is added to
+wpa_supplicant configuration. If the NFC tag contains a password token,
+the token is added to the WPS Registrar component. This information can
+then be used with wps_reg command (when the NFC password token was from
+an AP) using a special value "nfc-pw" in place of the PIN parameter. If
+the ER functionality has been started (wps_er_start), the NFC password
+token is used to enable enrollment of a new station (that was the source
+of the NFC password token).
diff --git a/wpa_supplicant/README-Windows.txt b/wpa_supplicant/README-Windows.txt
index 292223d..7288abd 100644
--- a/wpa_supplicant/README-Windows.txt
+++ b/wpa_supplicant/README-Windows.txt
@@ -4,13 +4,8 @@
Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
-This program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option.
-
-This product includes software developed by the OpenSSL Project
-for use in the OpenSSL Toolkit (http://www.openssl.org/). This
-product includes cryptographic software written by Eric Young
-(eay@cryptsoft.com).
+This program is licensed under the BSD license (the one with
+advertisement clause removed).
wpa_supplicant has support for being used as a WPA/WPA2/IEEE 802.1X
@@ -35,20 +30,6 @@
- WPA2-EAP, TKIP, CCMP, TKIP+CCMP
-Binary version
---------------
-
-Compiled binary version of the wpa_supplicant and additional tools is
-available from http://w1.fi/wpa_supplicant/. These binaries can be
-used after installing WinPcap.
-
-wpa_gui uses Qt 4 framework and may need additional dynamic libraries
-(DLLs). These libraries are available from
-http://w1.fi/wpa_supplicant/qt4/wpa_gui-qt433-windows-dll.zip
-You can copy the DLL files from this ZIP package into the same directory
-with wpa_gui.exe to allow wpa_gui to be started.
-
-
Building wpa_supplicant with mingw
----------------------------------
@@ -316,135 +297,3 @@
See win_example.reg for an example on how to setup wpasvc.exe
parameters in registry. It can also be imported to registry as a
starting point for the configuration.
-
-
-
-License information for third party software used in this product:
-
- OpenSSL License
- ---------------
-
-/* ====================================================================
- * Copyright (c) 1998-2004 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
- Original SSLeay License
- -----------------------
-
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-
-
- Qt Open Source Edition
- ----------------------
-
-The Qt GUI Toolkit is Copyright (C) 1994-2007 Trolltech ASA.
-Qt Open Source Edition is licensed under GPL version 2.
-
-Source code for the library is available at
-http://w1.fi/wpa_supplicant/qt4/qt-win-opensource-src-4.3.3.zip
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 5aa4fcc..fc0614d 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -55,11 +55,6 @@
# Set include directory to the madwifi source tree
#CFLAGS += -I../../madwifi
-# Driver interface for Prism54 driver
-# (Note: Prism54 is not yet supported, i.e., this will not work as-is and is
-# for developers only)
-#CONFIG_DRIVER_PRISM54=y
-
# Driver interface for ndiswrapper
# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
#CONFIG_DRIVER_NDISWRAPPER=y
@@ -83,6 +78,11 @@
#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
+# replacement for WEXT and its use allows wpa_supplicant to properly control
+# the driver to improve existing functionality like roaming and to support new
+# functionality.
#CONFIG_DRIVER_WEXT=y
# Driver interface for Linux drivers using the nl80211 kernel interface
@@ -93,6 +93,8 @@
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
# Driver interface for Windows NDIS
#CONFIG_DRIVER_NDIS=y
@@ -113,11 +115,6 @@
# Driver interface for development testing
#CONFIG_DRIVER_TEST=y
-# Include client MLME (management frame processing) for test driver
-# This can be used to test MLME operations in hostapd with the test interface.
-# space.
-#CONFIG_CLIENT_MLME=y
-
# Driver interface for wired Ethernet drivers
#CONFIG_DRIVER_WIRED=y
@@ -127,6 +124,10 @@
# Driver interface for no driver (e.g., WPS ER only)
#CONFIG_DRIVER_NONE=y
+# Solaris libraries
+#LIBS += -lsocket -ldlpi -lnsl
+#LIBS_c += -lsocket
+
# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
# included)
CONFIG_IEEE8021X_EAPOL=y
@@ -165,6 +166,9 @@
# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
#CONFIG_EAP_PSK=y
+# EAP-pwd (secure authentication using only a password)
+CONFIG_EAP_PWD=y
+
# EAP-PAX
#CONFIG_EAP_PAX=y
@@ -196,13 +200,15 @@
CONFIG_WPS=y
# Enable WSC 2.0 support
CONFIG_WPS2=y
+# Enable WPS external registrar functionality
+#CONFIG_WPS_ER=y
+# Disable credentials for an open network by default when acting as a WPS
+# registrar.
+#CONFIG_WPS_REG_DISABLE_OPEN=y
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
-# EAP-PWD
-CONFIG_EAP_PWD=y
-
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
@@ -215,6 +221,9 @@
# Enable this if EAP-SIM or EAP-AKA is included
#CONFIG_PCSC=y
+# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
+#CONFIG_HT_OVERRIDES=y
+
# Development testing
#CONFIG_EAPOL_TEST=y
@@ -233,6 +242,10 @@
# the resulting binary.
#CONFIG_READLINE=y
+# Include internal line edit mode in wpa_cli. This can be used as a replacement
+# for GNU Readline to provide limited command line editing and history support.
+CONFIG_WPA_CLI_EDIT=y
+
# Remove debugging code that is printing out debug message to stdout.
# This can be used to reduce the size of the wpa_supplicant considerably
# if debugging code is not needed. The size reduction can be around 35%
@@ -294,6 +307,9 @@
# eloop_none = Empty template
CONFIG_ELOOP=eloop
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
# Select layer 2 packet implementation
# linux = Linux packet socket (default)
# pcap = libpcap/libdnet/WinPcap
@@ -314,18 +330,24 @@
# Select TLS implementation
# openssl = OpenSSL (default)
-# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
+# gnutls = GnuTLS
# internal = Internal TLSv1 implementation (experimental)
# none = Empty template
#CONFIG_TLS=openssl
-# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
-# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
-# even though the core GnuTLS library is released under LGPL, this extra
-# library uses GPL and as such, the terms of GPL apply to the combination
-# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
-# apply for distribution of the resulting binary.
-#CONFIG_GNUTLS_EXTRA=y
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used. It should be noted that some existing TLS v1.0 -based
+# implementation may not be compatible with TLS v1.1 message (ClientHello is
+# sent prior to negotiating which version will be used)
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms. It should be
+# noted that some existing TLS v1.0 -based implementation may not be compatible
+# with TLS v1.2 message (ClientHello is sent prior to negotiating which version
+# will be used)
+#CONFIG_TLSV12=y
# If CONFIG_TLS=internal is used, additional library and include paths are
# needed for LibTomMath. Alternatively, an integrated, minimal version of
@@ -357,7 +379,7 @@
# (fi.w1.hostap.wpa_supplicant1)
#CONFIG_CTRL_IFACE_DBUS_NEW=y
-# Add introspection support for new DBus control interface (requires libxml2)
+# Add introspection support for new DBus control interface
#CONFIG_CTRL_IFACE_DBUS_INTRO=y
# Add support for loading EAP methods dynamically as shared libraries.
@@ -387,7 +409,19 @@
# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
#CONFIG_DEBUG_FILE=y
-# Add support for writing debug log to Android logcat instead of standard output
+# Send debug messages to syslog instead of stdout
+#CONFIG_DEBUG_SYSLOG=y
+# Set syslog facility for debug messages
+#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
+
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
+# Add support for writing debug log to Android logcat instead of standard
+# output
CONFIG_ANDROID_LOG=y
# Enable privilege separation (see README 'Privilege separation' for details)
@@ -397,11 +431,67 @@
# MIC error reports by a random amount of time between 0 and 60 seconds
#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, uncomment these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, uncomment these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# wpa_supplicant depends on strong random number generation being available
+# from the operating system. os_get_random() function is used to fetch random
+# data when needed, e.g., for key generation. On Linux and BSD systems, this
+# works by reading /dev/urandom. It should be noted that the OS entropy pool
+# needs to be properly initialized before wpa_supplicant is started. This is
+# important especially on embedded devices that do not have a hardware random
+# number generator and may by default start up with minimal entropy available
+# for random number generation.
+#
+# As a safety net, wpa_supplicant is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data fetched
+# from the OS. This by itself is not considered to be very strong, but it may
+# help in cases where the system pool is not initialized properly. However, it
+# is very strongly recommended that the system pool is initialized with enough
+# entropy either by using hardware assisted random number generator or by
+# storing state over device reboots.
+#
+# wpa_supplicant can be configured to maintain its own entropy store over
+# restarts to enhance random number generation. This is not perfect, but it is
+# much more secure than using the same sequence of random numbers after every
+# reboot. This can be enabled with -e<entropy file> command line option. The
+# specified file needs to be readable and writable by wpa_supplicant.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal wpa_supplicant random pool can be
+# disabled. This will save some in binary size and CPU use. However, this
+# should only be considered for builds that are known to be used on devices
+# that meet the requirements described above.
+#CONFIG_NO_RANDOM_POOL=y
+
+# IEEE 802.11n (High Throughput) support (mainly for AP mode)
+CONFIG_IEEE80211N=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks (GAS/ANQP to learn more about the networks and network
+# selection based on available credentials).
+#CONFIG_INTERWORKING=y
+
# Disable roaming in wpa_supplicant
CONFIG_NO_ROAMING=y
# Enable P2P
-# IEEE 802.11n (High Throughput) support (mainly for AP mode)
-CONFIG_IEEE80211N=y
CONFIG_P2P=y
CONFIG_AP=y
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 6046249..f9e0045 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -81,14 +81,23 @@
*/
if (wpa_s->hw.modes) {
struct hostapd_hw_modes *mode = NULL;
- int i;
+ int i, no_ht = 0;
for (i = 0; i < wpa_s->hw.num_modes; i++) {
if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
mode = &wpa_s->hw.modes[i];
break;
}
}
- if (mode && mode->ht_capab) {
+
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht) {
+ conf->ieee80211n = 0;
+ conf->ht_capab = 0;
+ no_ht = 1;
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
+ if (!no_ht && mode && mode->ht_capab) {
conf->ieee80211n = 1;
/*
@@ -145,6 +154,8 @@
bss->ssid.ssid_len = ssid->ssid_len;
bss->ssid.ssid_set = 1;
+ bss->ignore_broadcast_ssid = ssid->ignore_broadcast_ssid;
+
if (ssid->auth_alg)
bss->auth_algs = ssid->auth_alg;
@@ -179,6 +190,12 @@
wep->keys_set = 1;
}
+ if (ssid->ap_max_inactivity)
+ bss->ap_max_inactivity = ssid->ap_max_inactivity;
+
+ if (ssid->dtim_period)
+ bss->dtim_period = ssid->dtim_period;
+
/* Select group cipher based on the enabled pairwise cipher suites */
pairwise = 0;
if (bss->wpa & 1)
@@ -238,7 +255,10 @@
* configuration */
#endif /* CONFIG_WPS2 */
bss->eap_server = 1;
- bss->wps_state = 2;
+
+ if (!ssid->ignore_broadcast_ssid)
+ bss->wps_state = 2;
+
bss->ap_setup_locked = 2;
if (wpa_s->conf->config_methods)
bss->config_methods = os_strdup(wpa_s->conf->config_methods);
@@ -261,6 +281,7 @@
else
os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
os_memcpy(bss->os_version, wpa_s->conf->os_version, 4);
+ bss->pbc_in_m1 = wpa_s->conf->pbc_in_m1;
no_wps:
#endif /* CONFIG_WPS */
@@ -349,11 +370,13 @@
static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
- const u8 *bssid, const u8 *ie, size_t ie_len)
+ const u8 *bssid, const u8 *ie, size_t ie_len,
+ int ssi_signal)
{
#ifdef CONFIG_P2P
struct wpa_supplicant *wpa_s = ctx;
- return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len);
+ return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
+ ssi_signal);
#else /* CONFIG_P2P */
return 0;
#endif /* CONFIG_P2P */
@@ -520,9 +543,8 @@
hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s;
#ifdef CONFIG_P2P
hapd_iface->bss[i]->p2p = wpa_s->global->p2p;
- hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(
- wpa_s, ssid->p2p_persistent_group,
- ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION);
+ hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(wpa_s,
+ ssid);
#endif /* CONFIG_P2P */
hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb;
hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s;
@@ -651,21 +673,6 @@
}
-static int wpa_supplicant_ap_wps_sta_cancel(struct hostapd_data *hapd,
- struct sta_info *sta, void *ctx)
-{
- if (sta && (sta->flags & WLAN_STA_WPS)) {
- ap_sta_deauthenticate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
- wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
- __func__, MAC2STR(sta->addr));
- return 1;
- }
-
- return 0;
-}
-
-
int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
{
struct wps_registrar *reg;
@@ -677,7 +684,7 @@
reg = wpa_s->ap_iface->bss[0]->wps->registrar;
reg_sel = wps_registrar_wps_cancel(reg);
wps_sta = ap_for_each_sta(wpa_s->ap_iface->bss[0],
- wpa_supplicant_ap_wps_sta_cancel, NULL);
+ ap_sta_wps_cancel, NULL);
if (!reg_sel && !wps_sta) {
wpa_printf(MSG_DEBUG, "No WPS operation in progress at this "
@@ -870,6 +877,26 @@
}
+int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr)
+{
+ if (wpa_s->ap_iface == NULL)
+ return -1;
+ return hostapd_ctrl_iface_disassociate(wpa_s->ap_iface->bss[0],
+ txtaddr);
+}
+
+
+int ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr)
+{
+ if (wpa_s->ap_iface == NULL)
+ return -1;
+ return hostapd_ctrl_iface_deauthenticate(wpa_s->ap_iface->bss[0],
+ txtaddr);
+}
+
+
int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen, int verbose)
{
@@ -930,6 +957,17 @@
}
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
+ int offset)
+{
+ if (!wpa_s->ap_iface)
+ return;
+
+ wpa_s->assoc_freq = freq;
+ hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
+}
+
+
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index f0eb67d..bc953d9 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -31,6 +31,10 @@
char *buf, size_t buflen);
int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
char *buf, size_t buflen);
+int ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr);
+int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr);
int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen, int verbose);
void ap_tx_status(void *ctx, const u8 *addr,
@@ -45,5 +49,7 @@
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
const u8 *addr);
void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
+ int offset);
#endif /* AP_H */
diff --git a/wpa_supplicant/autoscan.c b/wpa_supplicant/autoscan.c
new file mode 100644
index 0000000..d0c040a
--- /dev/null
+++ b/wpa_supplicant/autoscan.c
@@ -0,0 +1,143 @@
+/*
+ * WPA Supplicant - auto scan
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "bss.h"
+#include "scan.h"
+#include "autoscan.h"
+
+#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+extern const struct autoscan_ops autoscan_exponential_ops;
+#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
+
+#ifdef CONFIG_AUTOSCAN_PERIODIC
+extern const struct autoscan_ops autoscan_periodic_ops;
+#endif /* CONFIG_AUTOSCAN_PERIODIC */
+
+static const struct autoscan_ops * autoscan_modules[] = {
+#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+ &autoscan_exponential_ops,
+#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
+#ifdef CONFIG_AUTOSCAN_PERIODIC
+ &autoscan_periodic_ops,
+#endif /* CONFIG_AUTOSCAN_PERIODIC */
+ NULL
+};
+
+
+static void request_scan(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->scan_req = 2;
+
+ if (wpa_supplicant_req_sched_scan(wpa_s))
+ wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0);
+}
+
+
+int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
+{
+ const char *name = wpa_s->conf->autoscan;
+ const char *params;
+ size_t nlen;
+ int i;
+ const struct autoscan_ops *ops = NULL;
+
+ if (wpa_s->autoscan && wpa_s->autoscan_priv)
+ return 0;
+
+ if (name == NULL)
+ return 0;
+
+ params = os_strchr(name, ':');
+ if (params == NULL) {
+ params = "";
+ nlen = os_strlen(name);
+ } else {
+ nlen = params - name;
+ params++;
+ }
+
+ for (i = 0; autoscan_modules[i]; i++) {
+ if (os_strncmp(name, autoscan_modules[i]->name, nlen) == 0) {
+ ops = autoscan_modules[i];
+ break;
+ }
+ }
+
+ if (ops == NULL) {
+ wpa_printf(MSG_ERROR, "autoscan: Could not find module "
+ "matching the parameter '%s'", name);
+ return -1;
+ }
+
+ wpa_s->autoscan_params = NULL;
+
+ wpa_s->autoscan_priv = ops->init(wpa_s, params);
+ if (wpa_s->autoscan_priv == NULL)
+ return -1;
+ wpa_s->autoscan = ops;
+
+ wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with "
+ "parameters '%s'", ops->name, params);
+ if (!req_scan)
+ return 0;
+
+ /*
+ * Cancelling existing scan requests, if any.
+ */
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
+
+ /*
+ * Firing first scan, which will lead to call autoscan_notify_scan.
+ */
+ request_scan(wpa_s);
+
+ return 0;
+}
+
+
+void autoscan_deinit(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+ wpa_printf(MSG_DEBUG, "autoscan: Deinitializing module '%s'",
+ wpa_s->autoscan->name);
+ wpa_s->autoscan->deinit(wpa_s->autoscan_priv);
+ wpa_s->autoscan = NULL;
+ wpa_s->autoscan_priv = NULL;
+
+ wpa_s->scan_interval = 5;
+ wpa_s->sched_scan_interval = 0;
+ }
+}
+
+
+int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ int interval;
+
+ if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+ interval = wpa_s->autoscan->notify_scan(wpa_s->autoscan_priv,
+ scan_res);
+
+ if (interval <= 0)
+ return -1;
+
+ wpa_s->scan_interval = interval;
+ wpa_s->sched_scan_interval = interval;
+
+ request_scan(wpa_s);
+ }
+
+ return 0;
+}
diff --git a/wpa_supplicant/autoscan.h b/wpa_supplicant/autoscan.h
new file mode 100644
index 0000000..e2a7652
--- /dev/null
+++ b/wpa_supplicant/autoscan.h
@@ -0,0 +1,49 @@
+/*
+ * WPA Supplicant - auto scan
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AUTOSCAN_H
+#define AUTOSCAN_H
+
+struct wpa_supplicant;
+
+struct autoscan_ops {
+ const char *name;
+
+ void * (*init)(struct wpa_supplicant *wpa_s, const char *params);
+ void (*deinit)(void *priv);
+
+ int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
+};
+
+#ifdef CONFIG_AUTOSCAN
+
+int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan);
+void autoscan_deinit(struct wpa_supplicant *wpa_s);
+int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
+
+#else /* CONFIG_AUTOSCAN */
+
+static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
+{
+ return 0;
+}
+
+static inline void autoscan_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ return 0;
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+#endif /* AUTOSCAN_H */
diff --git a/wpa_supplicant/autoscan_exponential.c b/wpa_supplicant/autoscan_exponential.c
new file mode 100644
index 0000000..424477b
--- /dev/null
+++ b/wpa_supplicant/autoscan_exponential.c
@@ -0,0 +1,104 @@
+/*
+ * WPA Supplicant - auto scan exponential module
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "autoscan.h"
+
+struct autoscan_exponential_data {
+ struct wpa_supplicant *wpa_s;
+ int base;
+ int limit;
+ int interval;
+};
+
+
+static int
+autoscan_exponential_get_params(struct autoscan_exponential_data *data,
+ const char *params)
+{
+ const char *pos;
+
+ if (params == NULL)
+ return -1;
+
+ data->base = atoi(params);
+
+ pos = os_strchr(params, ':');
+ if (pos == NULL)
+ return -1;
+
+ pos++;
+ data->limit = atoi(pos);
+
+ return 0;
+}
+
+
+static void * autoscan_exponential_init(struct wpa_supplicant *wpa_s,
+ const char *params)
+{
+ struct autoscan_exponential_data *data;
+
+ data = os_zalloc(sizeof(struct autoscan_exponential_data));
+ if (data == NULL)
+ return NULL;
+
+ if (autoscan_exponential_get_params(data, params) < 0) {
+ os_free(data);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "autoscan exponential: base exponential is %d "
+ "and limit is %d", data->base, data->limit);
+
+ data->wpa_s = wpa_s;
+
+ return data;
+}
+
+
+static void autoscan_exponential_deinit(void *priv)
+{
+ struct autoscan_exponential_data *data = priv;
+
+ os_free(data);
+}
+
+
+static int autoscan_exponential_notify_scan(void *priv,
+ struct wpa_scan_results *scan_res)
+{
+ struct autoscan_exponential_data *data = priv;
+
+ wpa_printf(MSG_DEBUG, "autoscan exponential: scan result "
+ "notification");
+
+ if (data->interval >= data->limit)
+ return data->limit;
+
+ if (data->interval <= 0)
+ data->interval = data->base;
+ else {
+ data->interval = data->interval * data->base;
+ if (data->interval > data->limit)
+ return data->limit;
+ }
+
+ return data->interval;
+}
+
+
+const struct autoscan_ops autoscan_exponential_ops = {
+ .name = "exponential",
+ .init = autoscan_exponential_init,
+ .deinit = autoscan_exponential_deinit,
+ .notify_scan = autoscan_exponential_notify_scan,
+};
diff --git a/wpa_supplicant/autoscan_periodic.c b/wpa_supplicant/autoscan_periodic.c
new file mode 100644
index 0000000..102d723
--- /dev/null
+++ b/wpa_supplicant/autoscan_periodic.c
@@ -0,0 +1,85 @@
+/*
+ * WPA Supplicant - auto scan periodic module
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "autoscan.h"
+
+
+struct autoscan_periodic_data {
+ int periodic_interval;
+};
+
+
+static int autoscan_periodic_get_params(struct autoscan_periodic_data *data,
+ const char *params)
+{
+ int interval;
+
+ if (params == NULL)
+ return -1;
+
+ interval = atoi(params);
+
+ if (interval < 0)
+ return -1;
+
+ data->periodic_interval = interval;
+
+ return 0;
+}
+
+
+static void * autoscan_periodic_init(struct wpa_supplicant *wpa_s,
+ const char *params)
+{
+ struct autoscan_periodic_data *data;
+
+ data = os_zalloc(sizeof(struct autoscan_periodic_data));
+ if (data == NULL)
+ return NULL;
+
+ if (autoscan_periodic_get_params(data, params) < 0) {
+ os_free(data);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "autoscan periodic: interval is %d",
+ data->periodic_interval);
+
+ return data;
+}
+
+
+static void autoscan_periodic_deinit(void *priv)
+{
+ struct autoscan_periodic_data *data = priv;
+
+ os_free(data);
+}
+
+
+static int autoscan_periodic_notify_scan(void *priv,
+ struct wpa_scan_results *scan_res)
+{
+ struct autoscan_periodic_data *data = priv;
+
+ wpa_printf(MSG_DEBUG, "autoscan periodic: scan result notification");
+
+ return data->periodic_interval;
+}
+
+
+const struct autoscan_ops autoscan_periodic_ops = {
+ .name = "periodic",
+ .init = autoscan_periodic_init,
+ .deinit = autoscan_periodic_deinit,
+ .notify_scan = autoscan_periodic_notify_scan,
+};
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index cbed2e0..580a82a 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -35,14 +35,15 @@
#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
-static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ const char *reason)
{
dl_list_del(&bss->list);
dl_list_del(&bss->list_id);
wpa_s->num_bss--;
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
- " SSID '%s'", bss->id, MAC2STR(bss->bssid),
- wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
#ifdef CONFIG_INTERWORKING
wpabuf_free(bss->anqp_venue_name);
@@ -53,6 +54,12 @@
wpabuf_free(bss->anqp_3gpp);
wpabuf_free(bss->anqp_domain_name);
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ wpabuf_free(bss->hs20_operator_friendly_name);
+ wpabuf_free(bss->hs20_wan_metrics);
+ wpabuf_free(bss->hs20_connection_capability);
+ wpabuf_free(bss->hs20_operating_class);
+#endif /* CONFIG_HS20 */
os_free(bss);
}
@@ -61,6 +68,8 @@
const u8 *ssid, size_t ssid_len)
{
struct wpa_bss *bss;
+ if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+ return NULL;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
bss->ssid_len == ssid_len &&
@@ -112,13 +121,21 @@
}
+static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ return bss == wpa_s->current_bss ||
+ os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
+ os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
+}
+
+
static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (!wpa_bss_known(wpa_s, bss)) {
- wpa_bss_remove(wpa_s, bss);
+ wpa_bss_remove(wpa_s, bss, __func__);
return 0;
}
}
@@ -127,21 +144,28 @@
}
-static void wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
+static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
{
+ struct wpa_bss *bss;
+
/*
* Remove the oldest entry that does not match with any configured
* network.
*/
if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
- return;
+ return 0;
/*
- * Remove the oldest entry since no better candidate for removal was
- * found.
+ * Remove the oldest entry that isn't currently in use.
*/
- wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
- struct wpa_bss, list));
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (!wpa_bss_in_use(wpa_s, bss)) {
+ wpa_bss_remove(wpa_s, bss, __func__);
+ return 0;
+ }
+ }
+
+ return -1;
}
@@ -170,8 +194,13 @@
" SSID '%s'",
bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
- if (wpa_s->num_bss > wpa_s->conf->bss_max_count)
- wpa_bss_remove_oldest(wpa_s);
+ if (wpa_s->num_bss > wpa_s->conf->bss_max_count &&
+ wpa_bss_remove_oldest(wpa_s) != 0) {
+ wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
+ "because all BSSes are in use. We should normally "
+ "not get here!", (int) wpa_s->num_bss);
+ wpa_s->conf->bss_max_count = wpa_s->num_bss;
+ }
}
@@ -326,6 +355,8 @@
nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
res->beacon_ie_len);
if (nbss) {
+ if (wpa_s->current_bss == bss)
+ wpa_s->current_bss = nbss;
bss = nbss;
os_memcpy(bss + 1, res + 1,
res->ie_len + res->beacon_ie_len);
@@ -340,14 +371,6 @@
}
-static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
-{
- return bss == wpa_s->current_bss ||
- os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
- os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
-}
-
-
void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
{
wpa_s->bss_update_idx++;
@@ -375,6 +398,18 @@
}
p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
+#ifdef CONFIG_P2P
+ if (p2p == NULL &&
+ wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+ /*
+ * If it's a P2P specific interface, then don't update
+ * the scan result without a P2P IE.
+ */
+ wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
+ " update for P2P interface", MAC2STR(res->bssid));
+ return;
+ }
+#endif /* CONFIG_P2P */
if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
return; /* Skip P2P listen discovery results here */
@@ -447,9 +482,7 @@
bss->scan_miss_count++;
if (bss->scan_miss_count >=
wpa_s->conf->bss_expiration_scan_count) {
- wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to "
- "no match in scan", bss->id);
- wpa_bss_remove(wpa_s, bss);
+ wpa_bss_remove(wpa_s, bss, "no match in scan");
}
}
}
@@ -471,9 +504,7 @@
continue;
if (os_time_before(&bss->last_update, &t)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to "
- "age", bss->id);
- wpa_bss_remove(wpa_s, bss);
+ wpa_bss_remove(wpa_s, bss, __func__);
} else
break;
}
@@ -510,7 +541,7 @@
dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
if (wpa_bss_in_use(wpa_s, bss))
continue;
- wpa_bss_remove(wpa_s, bss);
+ wpa_bss_remove(wpa_s, bss, __func__);
}
}
@@ -526,6 +557,8 @@
const u8 *bssid)
{
struct wpa_bss *bss;
+ if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+ return NULL;
dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
return bss;
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 2bc9f82..65e962b 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -19,24 +19,6 @@
#define WPA_BSS_ASSOCIATED BIT(5)
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
-#define WPA_BSS_MASK_ALL 0xFFFFFFFF
-#define WPA_BSS_MASK_ID BIT(0)
-#define WPA_BSS_MASK_BSSID BIT(1)
-#define WPA_BSS_MASK_FREQ BIT(2)
-#define WPA_BSS_MASK_BEACON_INT BIT(3)
-#define WPA_BSS_MASK_CAPABILITIES BIT(4)
-#define WPA_BSS_MASK_QUAL BIT(5)
-#define WPA_BSS_MASK_NOISE BIT(6)
-#define WPA_BSS_MASK_LEVEL BIT(7)
-#define WPA_BSS_MASK_TSF BIT(8)
-#define WPA_BSS_MASK_AGE BIT(9)
-#define WPA_BSS_MASK_IE BIT(10)
-#define WPA_BSS_MASK_FLAGS BIT(11)
-#define WPA_BSS_MASK_SSID BIT(12)
-#define WPA_BSS_MASK_WPS_SCAN BIT(13)
-#define WPA_BSS_MASK_P2P_SCAN BIT(14)
-#define WPA_BSS_MASK_INTERNETW BIT(15)
-
/**
* struct wpa_bss - BSS table
* @list: List entry for struct wpa_supplicant::bss
@@ -87,6 +69,12 @@
struct wpabuf *anqp_3gpp;
struct wpabuf *anqp_domain_name;
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ struct wpabuf *hs20_operator_friendly_name;
+ struct wpabuf *hs20_wan_metrics;
+ struct wpabuf *hs20_connection_capability;
+ struct wpabuf *hs20_operating_class;
+#endif /* CONFIG_HS20 */
size_t ie_len;
size_t beacon_ie_len;
/* followed by ie_len octets of IEs */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index d36d027..a795c41 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,6 +13,7 @@
#include "crypto/sha1.h"
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
+#include "p2p/p2p.h"
#include "config.h"
@@ -1130,6 +1131,7 @@
wpa_hexdump(MSG_MSGDUMP, "eap methods",
(u8 *) methods, num_methods * sizeof(*methods));
+ os_free(ssid->eap.eap_methods);
ssid->eap.eap_methods = methods;
return errors ? -1 : 0;
}
@@ -1277,6 +1279,11 @@
os_free(buf);
return -1;
}
+ if (*len && *len != 5 && *len != 13 && *len != 16) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - "
+ "this network block will be ignored",
+ line, (unsigned int) *len);
+ }
os_memcpy(key, buf, *len);
os_free(buf);
res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
@@ -1556,6 +1563,7 @@
{ FUNC_KEY(psk) },
{ FUNC(proto) },
{ FUNC(key_mgmt) },
+ { INT(bg_scan_period) },
{ FUNC(pairwise) },
{ FUNC(group) },
{ FUNC(auth_alg) },
@@ -1622,6 +1630,7 @@
{ INT_RANGE(frequency, 0, 10000) },
{ INT(wpa_ptk_rekey) },
{ STR(bgscan) },
+ { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
#ifdef CONFIG_P2P
{ FUNC(p2p_client_list) },
#endif /* CONFIG_P2P */
@@ -1633,6 +1642,8 @@
{ INT_RANGE(ampdu_density, -1, 7) },
{ STR(ht_mcs) },
#endif /* CONFIG_HT_OVERRIDES */
+ { INT(ap_max_inactivity) },
+ { INT(dtim_period) },
};
#ifdef WPA_UNICODE_SSID
@@ -1701,13 +1712,14 @@
return -1;
for (prio = 0; prio < config->num_prio; prio++) {
- if (nlist[prio]->priority < ssid->priority)
+ if (nlist[prio]->priority < ssid->priority) {
+ os_memmove(&nlist[prio + 1], &nlist[prio],
+ (config->num_prio - prio) *
+ sizeof(struct wpa_ssid *));
break;
+ }
}
- os_memmove(&nlist[prio + 1], &nlist[prio],
- (config->num_prio - prio) * sizeof(struct wpa_ssid *));
-
nlist[prio] = ssid;
config->num_prio++;
config->pssid = nlist;
@@ -1816,6 +1828,22 @@
}
+void wpa_config_free_cred(struct wpa_cred *cred)
+{
+ os_free(cred->realm);
+ os_free(cred->username);
+ os_free(cred->password);
+ os_free(cred->ca_cert);
+ os_free(cred->client_cert);
+ os_free(cred->private_key);
+ os_free(cred->private_key_passwd);
+ os_free(cred->imsi);
+ os_free(cred->milenage);
+ os_free(cred->domain);
+ os_free(cred);
+}
+
+
/**
* wpa_config_free - Free configuration data
* @config: Configuration data from wpa_config_read()
@@ -1829,6 +1857,7 @@
struct wpa_config_blob *blob, *prevblob;
#endif /* CONFIG_NO_CONFIG_BLOBS */
struct wpa_ssid *ssid, *prev = NULL;
+ struct wpa_cred *cred, *cprev;
ssid = config->ssid;
while (ssid) {
@@ -1837,6 +1866,13 @@
wpa_config_free_ssid(prev);
}
+ cred = config->cred;
+ while (cred) {
+ cprev = cred;
+ cred = cred->next;
+ wpa_config_free_cred(cprev);
+ }
+
#ifndef CONFIG_NO_CONFIG_BLOBS
blob = config->blobs;
prevblob = NULL;
@@ -1847,11 +1883,14 @@
}
#endif /* CONFIG_NO_CONFIG_BLOBS */
+ wpabuf_free(config->wps_vendor_ext_m1);
os_free(config->ctrl_interface);
os_free(config->ctrl_interface_group);
os_free(config->opensc_engine_path);
os_free(config->pkcs11_engine_path);
os_free(config->pkcs11_module_path);
+ os_free(config->pcsc_reader);
+ os_free(config->pcsc_pin);
os_free(config->driver_param);
os_free(config->device_name);
os_free(config->manufacturer);
@@ -1861,12 +1900,11 @@
os_free(config->config_methods);
os_free(config->p2p_ssid_postfix);
os_free(config->pssid);
- os_free(config->home_realm);
- os_free(config->home_username);
- os_free(config->home_password);
- os_free(config->home_ca_cert);
- os_free(config->home_imsi);
- os_free(config->home_milenage);
+ os_free(config->p2p_pref_chan);
+ os_free(config->autoscan);
+ wpabuf_free(config->wps_nfc_dh_pubkey);
+ wpabuf_free(config->wps_nfc_dh_privkey);
+ wpabuf_free(config->wps_nfc_dev_pw);
#ifdef ANDROID_P2P
os_free(config->prioritize);
#endif
@@ -1997,6 +2035,7 @@
ssid->pairwise_cipher = DEFAULT_PAIRWISE;
ssid->group_cipher = DEFAULT_GROUP;
ssid->key_mgmt = DEFAULT_KEY_MGMT;
+ ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
#ifdef IEEE8021X_EAPOL
ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
@@ -2241,6 +2280,168 @@
}
+int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
+ const char *value, int line)
+{
+ char *val;
+ size_t len;
+
+ if (os_strcmp(var, "priority") == 0) {
+ cred->priority = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "pcsc") == 0) {
+ cred->pcsc = atoi(value);
+ return 0;
+ }
+
+ val = wpa_config_parse_string(value, &len);
+ if (val == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
+ "value '%s'.", line, var, value);
+ return -1;
+ }
+
+ if (os_strcmp(var, "realm") == 0) {
+ os_free(cred->realm);
+ cred->realm = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "username") == 0) {
+ os_free(cred->username);
+ cred->username = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "password") == 0) {
+ os_free(cred->password);
+ cred->password = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "ca_cert") == 0) {
+ os_free(cred->ca_cert);
+ cred->ca_cert = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "client_cert") == 0) {
+ os_free(cred->client_cert);
+ cred->client_cert = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "private_key") == 0) {
+ os_free(cred->private_key);
+ cred->private_key = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "private_key_passwd") == 0) {
+ os_free(cred->private_key_passwd);
+ cred->private_key_passwd = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "imsi") == 0) {
+ os_free(cred->imsi);
+ cred->imsi = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "milenage") == 0) {
+ os_free(cred->milenage);
+ cred->milenage = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "domain") == 0) {
+ os_free(cred->domain);
+ cred->domain = val;
+ return 0;
+ }
+
+ if (line) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
+ line, var);
+ }
+
+ os_free(val);
+
+ return -1;
+}
+
+
+struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id)
+{
+ struct wpa_cred *cred;
+
+ cred = config->cred;
+ while (cred) {
+ if (id == cred->id)
+ break;
+ cred = cred->next;
+ }
+
+ return cred;
+}
+
+
+struct wpa_cred * wpa_config_add_cred(struct wpa_config *config)
+{
+ int id;
+ struct wpa_cred *cred, *last = NULL;
+
+ id = -1;
+ cred = config->cred;
+ while (cred) {
+ if (cred->id > id)
+ id = cred->id;
+ last = cred;
+ cred = cred->next;
+ }
+ id++;
+
+ cred = os_zalloc(sizeof(*cred));
+ if (cred == NULL)
+ return NULL;
+ cred->id = id;
+ if (last)
+ last->next = cred;
+ else
+ config->cred = cred;
+
+ return cred;
+}
+
+
+int wpa_config_remove_cred(struct wpa_config *config, int id)
+{
+ struct wpa_cred *cred, *prev = NULL;
+
+ cred = config->cred;
+ while (cred) {
+ if (id == cred->id)
+ break;
+ prev = cred;
+ cred = cred->next;
+ }
+
+ if (cred == NULL)
+ return -1;
+
+ if (prev)
+ prev->next = cred->next;
+ else
+ config->cred = cred->next;
+
+ wpa_config_free_cred(cred);
+ return 0;
+}
+
+
#ifndef CONFIG_NO_CONFIG_BLOBS
/**
* wpa_config_get_blob - Get a named configuration blob
@@ -2454,6 +2655,35 @@
}
+static int wpa_global_config_parse_bin(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *pos)
+{
+ size_t len;
+ struct wpabuf **dst, *tmp;
+
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+
+ tmp = wpabuf_alloc(len / 2);
+ if (tmp == NULL)
+ return -1;
+
+ if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
+ wpabuf_free(tmp);
+ return -1;
+ }
+
+ dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
+ wpabuf_free(*dst);
+ *dst = tmp;
+ wpa_printf(MSG_DEBUG, "%s", data->name);
+
+ return 0;
+}
+
+
static int wpa_config_process_country(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
@@ -2528,6 +2758,43 @@
return 0;
}
+
+static int wpa_config_process_wps_vendor_ext_m1(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ struct wpabuf *tmp;
+ int len = os_strlen(pos) / 2;
+ u8 *p;
+
+ if (!len) {
+ wpa_printf(MSG_ERROR, "Line %d: "
+ "invalid wps_vendor_ext_m1", line);
+ return -1;
+ }
+
+ tmp = wpabuf_alloc(len);
+ if (tmp) {
+ p = wpabuf_put(tmp, len);
+
+ if (hexstr2bin(pos, p, len)) {
+ wpa_printf(MSG_ERROR, "Line %d: "
+ "invalid wps_vendor_ext_m1", line);
+ wpabuf_free(tmp);
+ return -1;
+ }
+
+ wpabuf_free(config->wps_vendor_ext_m1);
+ config->wps_vendor_ext_m1 = tmp;
+ } else {
+ wpa_printf(MSG_ERROR, "Can not allocate "
+ "memory for wps_vendor_ext_m1");
+ return -1;
+ }
+
+ return 0;
+}
+
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
@@ -2551,6 +2818,55 @@
config->num_sec_device_types++;
return 0;
}
+
+
+static int wpa_config_process_p2p_pref_chan(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ struct p2p_channel *pref = NULL, *n;
+ unsigned int num = 0;
+ const char *pos2;
+ u8 op_class, chan;
+
+ /* format: class:chan,class:chan,... */
+
+ while (*pos) {
+ op_class = atoi(pos);
+ pos2 = os_strchr(pos, ':');
+ if (pos2 == NULL)
+ goto fail;
+ pos2++;
+ chan = atoi(pos2);
+
+ n = os_realloc(pref, (num + 1) * sizeof(struct p2p_channel));
+ if (n == NULL)
+ goto fail;
+ pref = n;
+ pref[num].op_class = op_class;
+ pref[num].chan = chan;
+ num++;
+
+ pos = os_strchr(pos2, ',');
+ if (pos == NULL)
+ break;
+ pos++;
+ }
+
+ os_free(config->p2p_pref_chan);
+ config->p2p_pref_chan = pref;
+ config->num_p2p_pref_chan = num;
+ wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs",
+ (u8 *) config->p2p_pref_chan,
+ config->num_p2p_pref_chan * sizeof(struct p2p_channel));
+
+ return 0;
+
+fail:
+ os_free(pref);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
+ return -1;
+}
#endif /* CONFIG_P2P */
@@ -2582,6 +2898,7 @@
#define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
#define STR(f) _STR(f), NULL, NULL
#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
+#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
static const struct global_parse_data global_fields[] = {
#ifdef CONFIG_CTRL_IFACE
@@ -2590,10 +2907,13 @@
#endif /* CONFIG_CTRL_IFACE */
{ INT_RANGE(eapol_version, 1, 2), 0 },
{ INT(ap_scan), 0 },
+ { INT(disable_scan_offload), 0 },
{ INT(fast_reauth), 0 },
{ STR(opensc_engine_path), 0 },
{ STR(pkcs11_engine_path), 0 },
{ STR(pkcs11_module_path), 0 },
+ { STR(pcsc_reader), 0 },
+ { STR(pcsc_pin), 0 },
{ STR(driver_param), 0 },
{ INT(dot11RSNAConfigPMKLifetime), 0 },
{ INT(dot11RSNAConfigPMKReauthThreshold), 0 },
@@ -2613,6 +2933,7 @@
{ FUNC(os_version), CFG_CHANGED_OS_VERSION },
{ STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
{ INT_RANGE(wps_cred_processing, 0, 2), 0 },
+ { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
{ FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
@@ -2625,6 +2946,7 @@
{ INT_RANGE(persistent_reconnect, 0, 1), 0 },
{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
{ INT(p2p_group_idle), 0 },
+ { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
#endif /* CONFIG_P2P */
#ifdef ANDROID_P2P
{ STR_RANGE(prioritize, 0, 32), CFG_CHANGED_IFACE_PRIORITY },
@@ -2636,15 +2958,18 @@
{ INT_RANGE(filter_ssids, 0, 1), 0 },
{ INT(max_num_sta), 0 },
{ INT_RANGE(disassoc_low_ack, 0, 1), 0 },
- { STR(home_realm), 0 },
- { STR(home_username), 0 },
- { STR(home_password), 0 },
- { STR(home_ca_cert), 0 },
- { STR(home_imsi), 0 },
- { STR(home_milenage), 0 },
+#ifdef CONFIG_HS20
+ { INT_RANGE(hs20, 0, 1), 0 },
+#endif /* CONFIG_HS20 */
{ INT_RANGE(interworking, 0, 1), 0 },
{ FUNC(hessid), 0 },
- { INT_RANGE(access_network_type, 0, 15), 0 }
+ { INT_RANGE(access_network_type, 0, 15), 0 },
+ { INT_RANGE(pbc_in_m1, 0, 1), 0 },
+ { STR(autoscan), 0 },
+ { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
+ { BIN(wps_nfc_dh_pubkey), 0 },
+ { BIN(wps_nfc_dh_privkey), 0 },
+ { BIN(wps_nfc_dev_pw), 0 }
};
#undef FUNC
@@ -2654,6 +2979,7 @@
#undef _STR
#undef STR
#undef STR_RANGE
+#undef BIN
#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 432a5d4..074e384 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration file structures
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -28,6 +28,129 @@
#include "wps/wps.h"
+struct wpa_cred {
+ /**
+ * next - Next credential in the list
+ *
+ * This pointer can be used to iterate over all credentials. The head
+ * of this list is stored in the cred field of struct wpa_config.
+ */
+ struct wpa_cred *next;
+
+ /**
+ * id - Unique id for the credential
+ *
+ * This identifier is used as a unique identifier for each credential
+ * block when using the control interface. Each credential is allocated
+ * an id when it is being created, either when reading the
+ * configuration file or when a new credential is added through the
+ * control interface.
+ */
+ int id;
+
+ /**
+ * 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
+ * (and similarly in struct wpa_ssid for network blocks) to change the
+ * Interworking automatic networking selection behavior. The matching
+ * network (based on either an enabled network block or a credential)
+ * with the highest priority value will be selected.
+ */
+ int priority;
+
+ /**
+ * pcsc - Use PC/SC and SIM/USIM card
+ */
+ int pcsc;
+
+ /**
+ * realm - Home Realm for Interworking
+ */
+ char *realm;
+
+ /**
+ * username - Username for Interworking network selection
+ */
+ char *username;
+
+ /**
+ * password - Password for Interworking network selection
+ */
+ char *password;
+
+ /**
+ * ca_cert - CA certificate for Interworking network selection
+ */
+ char *ca_cert;
+
+ /**
+ * client_cert - File path to client certificate file (PEM/DER)
+ *
+ * This field is used with Interworking networking selection for a case
+ * where client certificate/private key is used for authentication
+ * (EAP-TLS). Full path to the file should be used since working
+ * directory may change when wpa_supplicant is run in the background.
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://blob_name.
+ */
+ char *client_cert;
+
+ /**
+ * private_key - File path to client private key file (PEM/DER/PFX)
+ *
+ * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+ * commented out. Both the private key and certificate will be read
+ * from the PKCS#12 file in this case. Full path to the file should be
+ * used since working directory may change when wpa_supplicant is run
+ * in the background.
+ *
+ * Windows certificate store can be used by leaving client_cert out and
+ * configuring private_key in one of the following formats:
+ *
+ * cert://substring_to_match
+ *
+ * hash://certificate_thumbprint_in_hex
+ *
+ * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+ *
+ * Note that when running wpa_supplicant as an application, the user
+ * certificate store (My user account) is used, whereas computer store
+ * (Computer account) is used when running wpasvc as a service.
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://blob_name.
+ */
+ char *private_key;
+
+ /**
+ * private_key_passwd - Password for private key file
+ */
+ char *private_key_passwd;
+
+ /**
+ * imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+ */
+ char *imsi;
+
+ /**
+ * milenage - Milenage parameters for SIM/USIM simulator in
+ * <Ki>:<OPc>:<SQN> format
+ */
+ char *milenage;
+
+ /**
+ * domain - Home service provider FQDN
+ *
+ * This is used to compare against the Domain Name List to figure out
+ * whether the AP is operated by the Home SP.
+ */
+ char *domain;
+};
+
+
#define CFG_CHANGED_DEVICE_NAME BIT(0)
#define CFG_CHANGED_CONFIG_METHODS BIT(1)
#define CFG_CHANGED_DEVICE_TYPE BIT(2)
@@ -41,8 +164,9 @@
#define CFG_CHANGED_VENDOR_EXTENSION BIT(10)
#define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
+#define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
#ifdef ANDROID_P2P
-#define CFG_CHANGED_IFACE_PRIORITY BIT(13)
+#define CFG_CHANGED_IFACE_PRIORITY BIT(14)
#endif
/**
@@ -75,6 +199,13 @@
int num_prio;
/**
+ * cred - Head of the credential list
+ *
+ * This is the head for the list of all the configured credentials.
+ */
+ struct wpa_cred *cred;
+
+ /**
* eapol_version - IEEE 802.1X/EAPOL version number
*
* wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which
@@ -116,6 +247,15 @@
int ap_scan;
/**
+ * disable_scan_offload - Disable automatic offloading of scan requests
+ *
+ * By default, %wpa_supplicant tries to offload scanning if the driver
+ * indicates support for this (sched_scan). This configuration
+ * parameter can be used to disable this offloading mechanism.
+ */
+ int disable_scan_offload;
+
+ /**
* ctrl_interface - Parameters for the control interface
*
* If this is specified, %wpa_supplicant will open a control interface
@@ -214,6 +354,23 @@
char *pkcs11_module_path;
/**
+ * pcsc_reader - PC/SC reader name prefix
+ *
+ * If not %NULL, PC/SC reader with a name that matches this prefix is
+ * initialized for SIM/USIM access. Empty string can be used to match
+ * the first available reader.
+ */
+ char *pcsc_reader;
+
+ /**
+ * pcsc_pin - PIN for USIM, GSM SIM, and smartcards
+ *
+ * This field is used to configure PIN for SIM/USIM for EAP-SIM and
+ * EAP-AKA. If left out, this will be asked through control interface.
+ */
+ char *pcsc_pin;
+
+ /**
* driver_param - Driver interface parameters
*
* This text string is passed to the selected driver interface with the
@@ -359,6 +516,10 @@
char *p2p_ssid_postfix;
int persistent_reconnect;
int p2p_intra_bss;
+ unsigned int num_p2p_pref_chan;
+ struct p2p_channel *p2p_pref_chan;
+
+ struct wpabuf *wps_vendor_ext_m1;
#define MAX_WPS_VENDOR_EXT 10
/**
@@ -377,9 +538,12 @@
* state indefinitely until explicitly removed. As a P2P client, the
* maximum idle time of P2P_MAX_CLIENT_IDLE seconds is enforced, i.e.,
* this parameter is mainly meant for GO use and for P2P client, it can
- * only be used to reduce the default timeout to smaller value.
+ * only be used to reduce the default timeout to smaller value. A
+ * special value -1 can be used to configure immediate removal of the
+ * group for P2P client role on any disconnection after the data
+ * connection has been established.
*/
- unsigned int p2p_group_idle;
+ int p2p_group_idle;
/**
* bss_max_count - Maximum number of BSS entries to keep in memory
@@ -452,35 +616,55 @@
u8 hessid[ETH_ALEN];
/**
- * home_realm - Home Realm for Interworking
+ * hs20 - Hotspot 2.0
*/
- char *home_realm;
+ int hs20;
/**
- * home_username - Username for Interworking network selection
+ * pbc_in_m1 - AP mode WPS probing workaround for PBC with Windows 7
+ *
+ * Windows 7 uses incorrect way of figuring out AP's WPS capabilities
+ * by acting as a Registrar and using M1 from the AP. The config
+ * methods attribute in that message is supposed to indicate only the
+ * configuration method supported by the AP in Enrollee role, i.e., to
+ * add an external Registrar. For that case, PBC shall not be used and
+ * as such, the PushButton config method is removed from M1 by default.
+ * If pbc_in_m1=1 is included in the configuration file, the PushButton
+ * config method is left in M1 (if included in config_methods
+ * parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from
+ * a label in the AP).
*/
- char *home_username;
+ int pbc_in_m1;
/**
- * home_password - Password for Interworking network selection
+ * autoscan - Automatic scan parameters or %NULL if none
+ *
+ * This is an optional set of parameters for automatic scanning
+ * within an interface in following format:
+ * <autoscan module name>:<module parameters>
*/
- char *home_password;
+ char *autoscan;
/**
- * home_ca_cert - CA certificate for Interworking network selection
+ * wps_nfc_dev_pw_id - NFC Device Password ID for password token
*/
- char *home_ca_cert;
+ int wps_nfc_dev_pw_id;
/**
- * home_imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+ * wps_nfc_dh_pubkey - NFC DH Public Key for password token
*/
- char *home_imsi;
+ struct wpabuf *wps_nfc_dh_pubkey;
/**
- * home_milenage - Milenage parameters for SIM/USIM simulator in
- * <Ki>:<OPc>:<SQN> format
+ * wps_nfc_dh_pubkey - NFC DH Private Key for password token
*/
- char *home_milenage;
+ struct wpabuf *wps_nfc_dh_privkey;
+
+ /**
+ * wps_nfc_dh_pubkey - NFC Device Password for password token
+ */
+ struct wpabuf *wps_nfc_dev_pw;
+
#ifdef ANDROID_P2P
/**
* prioritize - Prioritize an Interface
@@ -522,6 +706,13 @@
void wpa_config_free_blob(struct wpa_config_blob *blob);
int wpa_config_remove_blob(struct wpa_config *config, const char *name);
+struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id);
+struct wpa_cred * wpa_config_add_cred(struct wpa_config *config);
+int wpa_config_remove_cred(struct wpa_config *config, int id);
+void wpa_config_free_cred(struct wpa_cred *cred);
+int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
+ const char *value, int line);
+
struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param);
#ifndef CONFIG_NO_STDOUT_DEBUG
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index a1955d4..8badc7b 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration backend: text file
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -16,6 +16,7 @@
#include "config.h"
#include "base64.h"
#include "uuid.h"
+#include "p2p/p2p.h"
/**
@@ -178,6 +179,61 @@
}
+static struct wpa_cred * wpa_config_read_cred(FILE *f, int *line, int id)
+{
+ struct wpa_cred *cred;
+ int errors = 0, end = 0;
+ char buf[256], *pos, *pos2;
+
+ wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new cred block", *line);
+ cred = os_zalloc(sizeof(*cred));
+ if (cred == NULL)
+ return NULL;
+ cred->id = id;
+
+ while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
+ if (os_strcmp(pos, "}") == 0) {
+ end = 1;
+ break;
+ }
+
+ pos2 = os_strchr(pos, '=');
+ if (pos2 == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid cred line "
+ "'%s'.", *line, pos);
+ errors++;
+ continue;
+ }
+
+ *pos2++ = '\0';
+ if (*pos2 == '"') {
+ if (os_strchr(pos2 + 1, '"') == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "quotation '%s'.", *line, pos2);
+ errors++;
+ continue;
+ }
+ }
+
+ if (wpa_config_set_cred(cred, pos, pos2, *line) < 0)
+ errors++;
+ }
+
+ if (!end) {
+ wpa_printf(MSG_ERROR, "Line %d: cred block was not "
+ "terminated properly.", *line);
+ errors++;
+ }
+
+ if (errors) {
+ wpa_config_free_cred(cred);
+ cred = NULL;
+ }
+
+ return cred;
+}
+
+
#ifndef CONFIG_NO_CONFIG_BLOBS
static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
const char *name)
@@ -264,11 +320,13 @@
struct wpa_config * wpa_config_read(const char *name)
{
FILE *f;
- char buf[256], *pos;
+ char buf[512], *pos;
int errors = 0, line = 0;
struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
+ struct wpa_cred *cred, *cred_tail = NULL, *cred_head = NULL;
struct wpa_config *config;
int id = 0;
+ int cred_id = 0;
config = wpa_config_alloc_empty(NULL, NULL);
if (config == NULL)
@@ -302,6 +360,20 @@
errors++;
continue;
}
+ } else if (os_strcmp(pos, "cred={") == 0) {
+ cred = wpa_config_read_cred(f, &line, cred_id++);
+ if (cred == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "parse cred block.", line);
+ errors++;
+ continue;
+ }
+ if (cred_head == NULL) {
+ cred_head = cred_tail = cred;
+ } else {
+ cred_tail->next = cred;
+ cred_tail = cred;
+ }
#ifndef CONFIG_NO_CONFIG_BLOBS
} else if (os_strncmp(pos, "blob-base64-", 12) == 0) {
if (wpa_config_process_blob(config, f, &line, pos + 12)
@@ -322,6 +394,7 @@
config->ssid = head;
wpa_config_debug_dump_networks(config);
+ config->cred = cred_head;
#ifndef WPA_IGNORE_CONFIG_ERRORS
if (errors) {
@@ -515,9 +588,12 @@
write_psk(f, ssid);
write_proto(f, ssid);
write_key_mgmt(f, ssid);
+ INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD);
write_pairwise(f, ssid);
write_group(f, ssid);
write_auth_alg(f, ssid);
+ STR(bgscan);
+ STR(autoscan);
#ifdef IEEE8021X_EAPOL
write_eap(f, ssid);
STR(identity);
@@ -583,6 +659,29 @@
}
+static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
+{
+ if (cred->priority)
+ fprintf(f, "\tpriority=%d\n", cred->priority);
+ if (cred->pcsc)
+ fprintf(f, "\tpcsc=%d\n", cred->pcsc);
+ if (cred->realm)
+ fprintf(f, "\trealm=\"%s\"\n", cred->realm);
+ if (cred->username)
+ fprintf(f, "\tusername=\"%s\"\n", cred->username);
+ if (cred->password)
+ fprintf(f, "\tpassword=\"%s\"\n", cred->password);
+ if (cred->ca_cert)
+ fprintf(f, "\tca_cert=\"%s\"\n", cred->ca_cert);
+ if (cred->imsi)
+ fprintf(f, "\timsi=\"%s\"\n", cred->imsi);
+ if (cred->milenage)
+ fprintf(f, "\tmilenage=\"%s\"\n", cred->milenage);
+ if (cred->domain)
+ fprintf(f, "\tdomain=\"%s\"\n", cred->domain);
+}
+
+
#ifndef CONFIG_NO_CONFIG_BLOBS
static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
{
@@ -599,6 +698,23 @@
#endif /* CONFIG_NO_CONFIG_BLOBS */
+static void write_global_bin(FILE *f, const char *field,
+ const struct wpabuf *val)
+{
+ size_t i;
+ const u8 *pos;
+
+ if (val == NULL)
+ return;
+
+ fprintf(f, "%s=", field);
+ pos = wpabuf_head(val);
+ for (i = 0; i < wpabuf_len(val); i++)
+ fprintf(f, "%02X", *pos++);
+ fprintf(f, "\n");
+}
+
+
static void wpa_config_write_global(FILE *f, struct wpa_config *config)
{
#ifdef CONFIG_CTRL_IFACE
@@ -612,6 +728,9 @@
fprintf(f, "eapol_version=%d\n", config->eapol_version);
if (config->ap_scan != DEFAULT_AP_SCAN)
fprintf(f, "ap_scan=%d\n", config->ap_scan);
+ if (config->disable_scan_offload)
+ fprintf(f, "disable_scan_offload=%d\n",
+ config->disable_scan_offload);
if (config->fast_reauth != DEFAULT_FAST_REAUTH)
fprintf(f, "fast_reauth=%d\n", config->fast_reauth);
if (config->opensc_engine_path)
@@ -623,6 +742,10 @@
if (config->pkcs11_module_path)
fprintf(f, "pkcs11_module_path=%s\n",
config->pkcs11_module_path);
+ if (config->pcsc_reader)
+ fprintf(f, "pcsc_reader=%s\n", config->pcsc_reader);
+ if (config->pcsc_pin)
+ fprintf(f, "pcsc_pin=%s\n", config->pcsc_pin);
if (config->driver_param)
fprintf(f, "driver_param=%s\n", config->driver_param);
if (config->dot11RSNAConfigPMKLifetime)
@@ -667,6 +790,16 @@
if (config->wps_cred_processing)
fprintf(f, "wps_cred_processing=%d\n",
config->wps_cred_processing);
+ if (config->wps_vendor_ext_m1) {
+ int i, len = wpabuf_len(config->wps_vendor_ext_m1);
+ const u8 *p = wpabuf_head_u8(config->wps_vendor_ext_m1);
+ if (len > 0) {
+ fprintf(f, "wps_vendor_ext_m1=");
+ for (i = 0; i < len; i++)
+ fprintf(f, "%02x", *p++);
+ fprintf(f, "\n");
+ }
+ }
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
if (config->p2p_listen_reg_class)
@@ -691,6 +824,16 @@
fprintf(f, "p2p_intra_bss=%u\n", config->p2p_intra_bss);
if (config->p2p_group_idle)
fprintf(f, "p2p_group_idle=%u\n", config->p2p_group_idle);
+ if (config->p2p_pref_chan) {
+ unsigned int i;
+ fprintf(f, "p2p_pref_chan=");
+ for (i = 0; i < config->num_p2p_pref_chan; i++) {
+ fprintf(f, "%s%u:%u", i > 0 ? "," : "",
+ config->p2p_pref_chan[i].op_class,
+ config->p2p_pref_chan[i].chan);
+ }
+ fprintf(f, "\n");
+ }
#endif /* CONFIG_P2P */
if (config->country[0] && config->country[1]) {
fprintf(f, "country=%c%c\n",
@@ -711,19 +854,11 @@
fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
if (config->disassoc_low_ack)
fprintf(f, "disassoc_low_ack=%u\n", config->disassoc_low_ack);
+#ifdef CONFIG_HS20
+ if (config->hs20)
+ fprintf(f, "hs20=1\n");
+#endif /* CONFIG_HS20 */
#ifdef CONFIG_INTERWORKING
- if (config->home_realm)
- fprintf(f, "home_realm=%s\n", config->home_realm);
- if (config->home_username)
- fprintf(f, "home_username=%s\n", config->home_username);
- if (config->home_password)
- fprintf(f, "home_password=%s\n", config->home_password);
- if (config->home_ca_cert)
- fprintf(f, "home_ca_cert=%s\n", config->home_ca_cert);
- if (config->home_imsi)
- fprintf(f, "home_imsi=%s\n", config->home_imsi);
- if (config->home_milenage)
- fprintf(f, "home_milenage=%s\n", config->home_milenage);
if (config->interworking)
fprintf(f, "interworking=%u\n", config->interworking);
if (!is_zero_ether_addr(config->hessid))
@@ -732,6 +867,14 @@
fprintf(f, "access_network_type=%d\n",
config->access_network_type);
#endif /* CONFIG_INTERWORKING */
+ if (config->pbc_in_m1)
+ fprintf(f, "pbc_in_m1=%u\n", config->pbc_in_m1);
+ if (config->wps_nfc_dev_pw_id)
+ fprintf(f, "wps_nfc_dev_pw_id=%d\n",
+ config->wps_nfc_dev_pw_id);
+ write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey);
+ write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey);
+ write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
@@ -742,6 +885,7 @@
#ifndef CONFIG_NO_CONFIG_WRITE
FILE *f;
struct wpa_ssid *ssid;
+ struct wpa_cred *cred;
#ifndef CONFIG_NO_CONFIG_BLOBS
struct wpa_config_blob *blob;
#endif /* CONFIG_NO_CONFIG_BLOBS */
@@ -757,6 +901,12 @@
wpa_config_write_global(f, config);
+ for (cred = config->cred; cred; cred = cred->next) {
+ fprintf(f, "\ncred={\n");
+ wpa_config_write_cred(f, cred);
+ fprintf(f, "}\n");
+ }
+
for (ssid = config->ssid; ssid; ssid = ssid->next) {
if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
continue; /* do not save temporary networks */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 3be6c26..59ec309 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -25,6 +25,7 @@
WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)
#define DEFAULT_FRAGMENT_SIZE 1398
+#define DEFAULT_BG_SCAN_PERIOD -1
#define DEFAULT_DISABLE_HT 0
#define DEFAULT_DISABLE_HT40 0
#define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
@@ -157,6 +158,12 @@
int key_mgmt;
/**
+ * bg_scan_period - Background scan period in seconds, 0 to disable, or
+ * -1 to indicate no change to default driver configuration
+ */
+ int bg_scan_period;
+
+ /**
* proto - Bitfield of allowed protocols, WPA_PROTO_*
*/
int proto;
@@ -377,6 +384,20 @@
char *bgscan;
/**
+ * ignore_broadcast_ssid - Hide SSID in AP mode
+ *
+ * Send empty SSID in beacons and ignore probe request frames that do
+ * not specify full SSID, i.e., require stations to know SSID.
+ * default: disabled (0)
+ * 1 = send empty (length=0) SSID in beacon and ignore probe request
+ * for broadcast SSID
+ * 2 = clear SSID (ASCII 0), but keep the original length (this may be
+ * required with some clients that do not support empty SSID) and
+ * ignore probe requests for broadcast SSID
+ */
+ int ignore_broadcast_ssid;
+
+ /**
* freq_list - Array of allowed frequencies or %NULL for all
*
* This is an optional zero-terminated array of frequencies in
@@ -476,6 +497,20 @@
*/
char *ht_mcs;
#endif /* CONFIG_HT_OVERRIDES */
+
+ /**
+ * ap_max_inactivity - Timeout in seconds to detect STA's inactivity
+ *
+ * This timeout value is used in AP mode to clean up inactive stations.
+ * By default: 300 seconds.
+ */
+ int ap_max_inactivity;
+
+ /**
+ * dtim_period - DTIM period in Beacon intervals
+ * By default: 2
+ */
+ int dtim_period;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index a22cce5..2224738 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-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -28,6 +28,7 @@
#include "ap.h"
#include "p2p_supplicant.h"
#include "p2p/p2p.h"
+#include "hs20_supplicant.h"
#include "notify.h"
#include "bss.h"
#include "scan.h"
@@ -35,6 +36,7 @@
#include "interworking.h"
#include "blacklist.h"
#include "wpas_glue.h"
+#include "autoscan.h"
extern struct wpa_driver_ops *wpa_drivers[];
@@ -59,7 +61,7 @@
num_ssid = 0;
ssid = wpa_s->conf->ssid;
while (ssid) {
- if (!ssid->disabled)
+ if (!wpas_network_disabled(wpa_s, ssid))
num_ssid++;
ssid = ssid->next;
}
@@ -81,7 +83,7 @@
i = 0;
ssid = wpa_s->conf->ssid;
while (ssid) {
- if (!ssid->disabled) {
+ if (!wpas_network_disabled(wpa_s, ssid)) {
params.ssids[i].ssid = ssid->ssid;
params.ssids[i].ssid_len = ssid->ssid_len;
params.num_ssids++;
@@ -114,6 +116,43 @@
}
+static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
+{
+ char *pos;
+ u8 addr[ETH_ALEN], *filter = NULL, *n;
+ size_t count = 0;
+
+ pos = val;
+ while (pos) {
+ if (*pos == '\0')
+ break;
+ if (hwaddr_aton(pos, addr)) {
+ os_free(filter);
+ return -1;
+ }
+ n = os_realloc(filter, (count + 1) * ETH_ALEN);
+ if (n == NULL) {
+ os_free(filter);
+ return -1;
+ }
+ filter = n;
+ os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
+ count++;
+
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ pos++;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
+ os_free(wpa_s->bssid_filter);
+ wpa_s->bssid_filter = filter;
+ wpa_s->bssid_filter_count = count;
+
+ return 0;
+}
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -197,8 +236,52 @@
ret = pno_start(wpa_s);
else
ret = pno_stop(wpa_s);
+ } else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
+ int disabled = atoi(value);
+ if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
+ ret = -1;
+ else if (disabled)
+ wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+ } else if (os_strcasecmp(cmd, "uapsd") == 0) {
+ if (os_strcmp(value, "disable") == 0)
+ wpa_s->set_sta_uapsd = 0;
+ else {
+ int be, bk, vi, vo;
+ char *pos;
+ /* format: BE,BK,VI,VO;max SP Length */
+ be = atoi(value);
+ pos = os_strchr(value, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ bk = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ vi = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ vo = atoi(pos);
+ /* ignore max SP Length for now */
+
+ wpa_s->set_sta_uapsd = 1;
+ wpa_s->sta_uapsd = 0;
+ if (be)
+ wpa_s->sta_uapsd |= BIT(0);
+ if (bk)
+ wpa_s->sta_uapsd |= BIT(1);
+ if (vi)
+ wpa_s->sta_uapsd |= BIT(2);
+ if (vo)
+ wpa_s->sta_uapsd |= BIT(3);
+ }
} else if (os_strcasecmp(cmd, "ps") == 0) {
ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
+ } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
+ ret = set_bssid_filter(wpa_s, value);
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -539,6 +622,80 @@
#endif /* CONFIG_WPS_OOB */
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ u8 bssid[ETH_ALEN], *_bssid = bssid;
+
+ if (cmd == NULL || cmd[0] == '\0')
+ _bssid = NULL;
+ else if (hwaddr_aton(cmd, bssid))
+ return -1;
+
+ return wpas_wps_start_nfc(wpa_s, _bssid);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_token(
+ struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+ int ndef;
+ struct wpabuf *buf;
+ int res;
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ buf = wpas_wps_nfc_token(wpa_s, ndef);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
+ struct wpa_supplicant *wpa_s, char *pos)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = wpas_wps_nfc_tag_read(wpa_s, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -735,6 +892,43 @@
ap.key_hex = new_key;
return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
}
+
+
+#ifdef CONFIG_WPS_NFC
+static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
+ struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+ int ndef;
+ struct wpabuf *buf;
+ int res;
+ char *uuid;
+
+ uuid = os_strchr(cmd, ' ');
+ if (uuid == NULL)
+ return -1;
+ *uuid++ = '\0';
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS_ER */
#endif /* CONFIG_WPS */
@@ -760,78 +954,6 @@
#endif /* CONFIG_IBSS_RSN */
-int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- const char *field,
- const char *value)
-{
-#ifdef IEEE8021X_EAPOL
- struct eap_peer_config *eap = &ssid->eap;
-
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
- wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
- (const u8 *) value, os_strlen(value));
-
- switch (wpa_supplicant_ctrl_req_from_string(field)) {
- case WPA_CTRL_REQ_EAP_IDENTITY:
- os_free(eap->identity);
- eap->identity = (u8 *) os_strdup(value);
- eap->identity_len = os_strlen(value);
- eap->pending_req_identity = 0;
- if (ssid == wpa_s->current_ssid)
- wpa_s->reassociate = 1;
- break;
- case WPA_CTRL_REQ_EAP_PASSWORD:
- os_free(eap->password);
- eap->password = (u8 *) os_strdup(value);
- eap->password_len = os_strlen(value);
- eap->pending_req_password = 0;
- if (ssid == wpa_s->current_ssid)
- wpa_s->reassociate = 1;
- break;
- case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
- os_free(eap->new_password);
- eap->new_password = (u8 *) os_strdup(value);
- eap->new_password_len = os_strlen(value);
- eap->pending_req_new_password = 0;
- if (ssid == wpa_s->current_ssid)
- wpa_s->reassociate = 1;
- break;
- case WPA_CTRL_REQ_EAP_PIN:
- os_free(eap->pin);
- eap->pin = os_strdup(value);
- eap->pending_req_pin = 0;
- if (ssid == wpa_s->current_ssid)
- wpa_s->reassociate = 1;
- break;
- case WPA_CTRL_REQ_EAP_OTP:
- os_free(eap->otp);
- eap->otp = (u8 *) os_strdup(value);
- eap->otp_len = os_strlen(value);
- os_free(eap->pending_req_otp);
- eap->pending_req_otp = NULL;
- eap->pending_req_otp_len = 0;
- break;
- case WPA_CTRL_REQ_EAP_PASSPHRASE:
- os_free(eap->private_key_passwd);
- eap->private_key_passwd = (u8 *) os_strdup(value);
- eap->pending_req_passphrase = 0;
- if (ssid == wpa_s->current_ssid)
- wpa_s->reassociate = 1;
- break;
- default:
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
- return -1;
- }
-
- return 0;
-#else /* IEEE8021X_EAPOL */
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
- return -1;
-#endif /* IEEE8021X_EAPOL */
-}
-
-
static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
char *rsp)
{
@@ -997,6 +1119,16 @@
return pos - buf;
pos += ret;
+#ifdef CONFIG_HS20
+ if (wpa_s->current_bss &&
+ wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE)) {
+ ret = os_snprintf(pos, end - pos, "hs20=1\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
+
if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
@@ -1507,6 +1639,14 @@
return -1;
pos += ret;
}
+#ifdef CONFIG_HS20
+ if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+ ret = os_snprintf(pos, end - pos, "[HS20]");
+ if (ret < 0 || ret >= end - pos)
+ return -1;
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
ret = os_snprintf(pos, end - pos, "\t%s",
wpa_ssid_txt(bss->ssid, bss->ssid_len));
@@ -1608,6 +1748,11 @@
"ENABLE_NETWORK with persistent P2P group");
return -1;
}
+
+ if (os_strstr(cmd, " no-connect")) {
+ ssid->disabled = 0;
+ return 0;
+ }
}
wpa_supplicant_enable_network(wpa_s, ssid);
@@ -1691,6 +1836,9 @@
}
eapol_sm_invalidate_cached_session(wpa_s->eapol);
if (wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_supplicant_disassociate(wpa_s,
@@ -1713,6 +1861,9 @@
}
if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
/*
* Invalidate the EAP session cache if the current or
* previously used network is removed.
@@ -1833,6 +1984,132 @@
}
+static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ char *pos, *end;
+ struct wpa_cred *cred;
+ int ret;
+
+ pos = buf;
+ end = buf + buflen;
+ ret = os_snprintf(pos, end - pos,
+ "cred id / realm / username / domain / imsi\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
+ cred->id, cred->realm ? cred->realm : "",
+ cred->username ? cred->username : "",
+ cred->domain ? cred->domain : "",
+ cred->imsi ? cred->imsi : "");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ cred = cred->next;
+ }
+
+ return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ struct wpa_cred *cred;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
+
+ cred = wpa_config_add_cred(wpa_s->conf);
+ if (cred == NULL)
+ return -1;
+
+ ret = os_snprintf(buf, buflen, "%d\n", cred->id);
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ int id;
+ struct wpa_cred *cred;
+
+ /* cmd: "<cred id>" or "all" */
+ if (os_strcmp(cmd, "all") == 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ id = cred->id;
+ cred = cred->next;
+ wpa_config_remove_cred(wpa_s->conf, id);
+ }
+ return 0;
+ }
+
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
+
+ cred = wpa_config_get_cred(wpa_s->conf, id);
+ if (cred == NULL ||
+ wpa_config_remove_cred(wpa_s->conf, id) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
+ id);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ int id;
+ struct wpa_cred *cred;
+ char *name, *value;
+
+ /* cmd: "<cred id> <variable name> <value>" */
+ name = os_strchr(cmd, ' ');
+ if (name == NULL)
+ return -1;
+ *name++ = '\0';
+
+ value = os_strchr(name, ' ');
+ if (value == NULL)
+ return -1;
+ *value++ = '\0';
+
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
+ id, name);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+ (u8 *) value, os_strlen(value));
+
+ cred = wpa_config_get_cred(wpa_s->conf, id);
+ if (cred == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
+ id);
+ return -1;
+ }
+
+ if (wpa_config_set_cred(cred, name, value, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
+ "variable '%s'", name);
+ return -1;
+ }
+
+ return 0;
+}
+
+
#ifndef CONFIG_NO_CONFIG_WRITE
static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
{
@@ -2254,9 +2531,7 @@
int ret;
char *pos, *end;
const u8 *ie, *ie2;
- struct os_time now;
- os_get_time(&now);
pos = buf;
end = buf + buflen;
@@ -2328,6 +2603,9 @@
}
if (mask & WPA_BSS_MASK_AGE) {
+ struct os_time now;
+
+ os_get_time(&now);
ret = os_snprintf(pos, end - pos, "age=%d\n",
(int) (now.sec - bss->last_update.sec));
if (ret < 0 || ret >= end - pos)
@@ -2394,6 +2672,14 @@
return 0;
pos += ret;
}
+#ifdef CONFIG_HS20
+ if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+ ret = os_snprintf(pos, end - pos, "[HS20]");
+ if (ret < 0 || ret >= end - pos)
+ return -1;
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
ret = os_snprintf(pos, end - pos, "\n");
if (ret < 0 || ret >= end - pos)
@@ -2444,19 +2730,28 @@
pos = anqp_add_hex(pos, end, "anqp_3gpp", bss->anqp_3gpp);
pos = anqp_add_hex(pos, end, "anqp_domain_name",
bss->anqp_domain_name);
+#ifdef CONFIG_HS20
+ pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
+ bss->hs20_operator_friendly_name);
+ pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
+ bss->hs20_wan_metrics);
+ pos = anqp_add_hex(pos, end, "hs20_connection_capability",
+ bss->hs20_connection_capability);
+#endif /* CONFIG_HS20 */
}
#endif /* CONFIG_INTERWORKING */
return pos - buf;
}
+
static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
const char *cmd, char *buf,
size_t buflen)
{
u8 bssid[ETH_ALEN];
size_t i;
- struct wpa_bss *bss = NULL;
+ struct wpa_bss *bss;
struct wpa_bss *bsslast = NULL;
struct dl_list *next;
int ret = 0;
@@ -2467,33 +2762,45 @@
if (os_strncmp(cmd, "RANGE=", 6) == 0) {
if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
- list_id);
+ list_id);
bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
list_id);
} else { /* N1-N2 */
- if ((ctmp = os_strchr(cmd + 6, '-')) != NULL) {
- int id1, id2;
- id1 = atoi(cmd + 6);
- bss = wpa_bss_get_id(wpa_s, id1);
- id2 = atoi(ctmp + 1);
- if (id2 == 0)
- bsslast = dl_list_last(&wpa_s->bss_id,
- struct wpa_bss,
- list_id);
- else
- bsslast = wpa_bss_get_id(wpa_s, id2);
- } else {
- wpa_printf(MSG_ERROR, "Wrong range format");
+ unsigned int id1, id2;
+
+ if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
+ wpa_printf(MSG_INFO, "Wrong BSS range "
+ "format");
return 0;
}
- }
- if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
- mask = strtoul(ctmp + 5, NULL, 0x10);
- if (mask == 0)
- mask = WPA_BSS_MASK_ALL;
+
+ id1 = atoi(cmd + 6);
+ bss = wpa_bss_get_id(wpa_s, id1);
+ id2 = atoi(ctmp + 1);
+ if (id2 == 0)
+ bsslast = dl_list_last(&wpa_s->bss_id,
+ struct wpa_bss,
+ list_id);
+ else {
+ bsslast = wpa_bss_get_id(wpa_s, id2);
+ if (bsslast == NULL && bss && id2 > id1) {
+ struct wpa_bss *tmp = bss;
+ for (;;) {
+ next = tmp->list_id.next;
+ if (next == &wpa_s->bss_id)
+ break;
+ tmp = dl_list_entry(
+ next, struct wpa_bss,
+ list_id);
+ if (tmp->id > id2)
+ break;
+ bsslast = tmp;
+ }
+ }
+ }
}
} else if (os_strcmp(cmd, "FIRST") == 0)
- bss = dl_list_first(&wpa_s->bss, struct wpa_bss, list);
+ bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
else if (os_strncmp(cmd, "ID-", 3) == 0) {
i = atoi(cmd + 3);
bss = wpa_bss_get_id(wpa_s, i);
@@ -2530,6 +2837,12 @@
}
}
+ if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
+ mask = strtoul(ctmp + 5, NULL, 0x10);
+ if (mask == 0)
+ mask = WPA_BSS_MASK_ALL;
+ }
+
if (bss == NULL)
return 0;
@@ -2564,10 +2877,7 @@
struct wpa_supplicant *wpa_s, char *cmd)
{
int scan_int = atoi(cmd);
- if (scan_int < 0)
- return -1;
- wpa_s->scan_interval = scan_int;
- return 0;
+ return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
}
@@ -2688,14 +2998,17 @@
enum p2p_wps_method wps_method;
int new_pin;
int ret;
- int persistent_group;
+ int persistent_group, persistent_id = -1;
int join;
int auth;
+ int automatic;
int go_intent = -1;
int freq = 0;
+ int pd;
- /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad] [persistent]
- * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] */
+ /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
+ * [persistent|persistent=<network id>]
+ * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -2706,8 +3019,23 @@
pos++;
persistent_group = os_strstr(pos, " persistent") != NULL;
+ pos2 = os_strstr(pos, " persistent=");
+ if (pos2) {
+ struct wpa_ssid *ssid;
+ persistent_id = atoi(pos2 + 12);
+ ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
+ if (ssid == NULL || ssid->disabled != 2 ||
+ ssid->mode != WPAS_MODE_P2P_GO) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+ "SSID id=%d for persistent P2P group (GO)",
+ persistent_id);
+ return -1;
+ }
+ }
join = os_strstr(pos, " join") != NULL;
auth = os_strstr(pos, " auth") != NULL;
+ automatic = os_strstr(pos, " auto") != NULL;
+ pd = os_strstr(pos, " provdisc") != NULL;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -2739,11 +3067,15 @@
if (os_strncmp(pos, "display", 7) == 0)
wps_method = WPS_PIN_DISPLAY;
}
+ if (!wps_pin_str_valid(pin)) {
+ os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
+ return 17;
+ }
}
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
- persistent_group, join, auth, go_intent,
- freq);
+ persistent_group, automatic, join,
+ auth, go_intent, freq, persistent_id, pd);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
@@ -2777,8 +3109,9 @@
{
u8 addr[ETH_ALEN];
char *pos;
+ enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
- /* <addr> <config method> [join] */
+ /* <addr> <config method> [join|auto] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -2788,8 +3121,12 @@
return -1;
pos++;
- return wpas_p2p_prov_disc(wpa_s, addr, pos,
- os_strstr(pos, "join") != NULL);
+ if (os_strstr(pos, " join") != NULL)
+ use = WPAS_P2P_PD_FOR_JOIN;
+ else if (os_strstr(pos, " auto") != NULL)
+ use = WPAS_P2P_PD_AUTO;
+
+ return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
}
@@ -2926,6 +3263,8 @@
static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
char *cmd)
{
+ if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
+ return -1;
wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
return 0;
}
@@ -3278,6 +3617,56 @@
}
+static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
+ const char *param)
+{
+ struct wpa_freq_range *freq = NULL, *n;
+ unsigned int count = 0, i;
+ const char *pos, *pos2, *pos3;
+
+ if (wpa_s->global->p2p == NULL)
+ return -1;
+
+ /*
+ * param includes comma separated frequency range.
+ * For example: 2412-2432,2462,5000-6000
+ */
+ pos = param;
+ while (pos && pos[0]) {
+ n = os_realloc(freq,
+ (count + 1) * sizeof(struct wpa_freq_range));
+ if (n == NULL) {
+ os_free(freq);
+ return -1;
+ }
+ freq = n;
+ freq[count].min = atoi(pos);
+ pos2 = os_strchr(pos, '-');
+ pos3 = os_strchr(pos, ',');
+ if (pos2 && (!pos3 || pos2 < pos3)) {
+ pos2++;
+ freq[count].max = atoi(pos2);
+ } else
+ freq[count].max = freq[count].min;
+ pos = pos3;
+ if (pos)
+ pos++;
+ count++;
+ }
+
+ for (i = 0; i < count; i++) {
+ wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
+ freq[i].min, freq[i].max);
+ }
+
+ os_free(wpa_s->global->p2p_disallow_freq);
+ wpa_s->global->p2p_disallow_freq = freq;
+ wpa_s->global->num_p2p_disallow_freq = count;
+ wpas_p2p_update_channel_list(wpa_s);
+ return 0;
+}
+
+
static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
{
char *param;
@@ -3356,7 +3745,7 @@
}
return 0;
}
-#ifdef ANDROID_P2P
+
if (os_strcmp(cmd, "conc_pref") == 0) {
if (os_strcmp(param, "sta") == 0)
wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
@@ -3367,10 +3756,10 @@
return -1;
}
wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
- "%s", param);
+ "%s", param);
return 0;
}
-#endif
+
if (os_strcmp(cmd, "force_long_sd") == 0) {
wpa_s->force_long_sd = atoi(param);
return 0;
@@ -3436,6 +3825,9 @@
return 0;
}
+ if (os_strcmp(cmd, "disallow_freq") == 0)
+ return p2p_ctrl_disallow_freq(wpa_s, param);
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
cmd);
@@ -3548,6 +3940,111 @@
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+
+static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
+{
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ char *pos;
+ u32 subtypes = 0;
+
+ used = hwaddr_aton2(dst, dst_addr);
+ if (used < 0)
+ return -1;
+ pos = dst + used;
+ for (;;) {
+ int num = atoi(pos);
+ if (num <= 0 || num > 31)
+ return -1;
+ subtypes |= BIT(num);
+ pos = os_strchr(pos + 1, ',');
+ if (pos == NULL)
+ break;
+ pos++;
+ }
+
+ if (subtypes == 0)
+ return -1;
+
+ return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
+}
+
+
+static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const char *realm)
+{
+ u8 *buf;
+ size_t rlen, len;
+ int ret;
+
+ rlen = os_strlen(realm);
+ len = 3 + rlen;
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+ buf[0] = 1; /* NAI Home Realm Count */
+ buf[1] = 0; /* Formatted in accordance with RFC 4282 */
+ buf[2] = rlen;
+ os_memcpy(buf + 3, realm, rlen);
+
+ ret = hs20_anqp_send_req(wpa_s, addr,
+ BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
+ buf, len);
+
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
+ char *dst)
+{
+ struct wpa_cred *cred = wpa_s->conf->cred;
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ u8 *buf;
+ size_t len;
+ int ret;
+
+ used = hwaddr_aton2(dst, dst_addr);
+ if (used < 0)
+ return -1;
+
+ while (dst[used] == ' ')
+ used++;
+ if (os_strncmp(dst + used, "realm=", 6) == 0)
+ return hs20_nai_home_realm_list(wpa_s, dst_addr,
+ dst + used + 6);
+
+ len = os_strlen(dst + used);
+
+ if (len == 0 && cred && cred->realm)
+ return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
+
+ if (len % 1)
+ return -1;
+ len /= 2;
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(dst + used, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ ret = hs20_anqp_send_req(wpa_s, dst_addr,
+ BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
+ buf, len);
+ os_free(buf);
+
+ return ret;
+}
+
+#endif /* CONFIG_HS20 */
+
+
static int wpa_supplicant_ctrl_iface_sta_autoconnect(
struct wpa_supplicant *wpa_s, char *cmd)
{
@@ -3556,6 +4053,36 @@
}
+#ifdef CONFIG_AUTOSCAN
+
+static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ enum wpa_states state = wpa_s->wpa_state;
+ char *new_params = NULL;
+
+ if (os_strlen(cmd) > 0) {
+ new_params = os_strdup(cmd);
+ if (new_params == NULL)
+ return -1;
+ }
+
+ os_free(wpa_s->conf->autoscan);
+ wpa_s->conf->autoscan = new_params;
+
+ if (wpa_s->conf->autoscan == NULL)
+ autoscan_deinit(wpa_s);
+ else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+ autoscan_init(wpa_s, 1);
+ else if (state == WPA_SCANNING)
+ wpa_supplicant_reinit_autoscan(wpa_s);
+
+ return 0;
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+
static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
@@ -3654,6 +4181,7 @@
eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
wpa_s->normal_scans = 0;
+ wpa_supplicant_reinit_autoscan(wpa_s);
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
else {
@@ -3663,6 +4191,7 @@
}
} else if (os_strcmp(buf, "RECONNECT") == 0) {
wpa_s->normal_scans = 0;
+ wpa_supplicant_reinit_autoscan(wpa_s);
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
else if (wpa_s->disconnected) {
@@ -3715,6 +4244,21 @@
if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
reply_len = -1;
#endif /* CONFIG_WPS_OOB */
+#ifdef CONFIG_WPS_NFC
+ } else if (os_strcmp(buf, "WPS_NFC") == 0) {
+ if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
+ if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
+ wpa_s, buf + 14, reply, reply_size);
+ } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
+ if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
+ buf + 17))
+ reply_len = -1;
+#endif /* CONFIG_WPS_NFC */
} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
reply_len = -1;
@@ -3759,6 +4303,11 @@
} else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+ } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
+ wpa_s, buf + 24, reply, reply_size);
+#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS_ER */
#endif /* CONFIG_WPS */
#ifdef CONFIG_IBSS_RSN
@@ -3873,6 +4422,14 @@
if (get_anqp(wpa_s, buf + 9) < 0)
reply_len = -1;
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
+ if (get_hs20_anqp(wpa_s, buf + 14) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
+ if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
+ reply_len = -1;
+#endif /* CONFIG_HS20 */
} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
{
if (wpa_supplicant_ctrl_iface_ctrl_rsp(
@@ -3898,19 +4455,30 @@
reply_len = wpa_supplicant_ctrl_iface_list_networks(
wpa_s, reply, reply_size);
} else if (os_strcmp(buf, "DISCONNECT") == 0) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
wpa_s->reassociate = 0;
wpa_s->disconnected = 1;
wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
} else if (os_strcmp(buf, "SCAN") == 0) {
- wpa_s->normal_scans = 0;
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
else {
if (!wpa_s->scanning &&
((wpa_s->wpa_state <= WPA_SCANNING) ||
(wpa_s->wpa_state == WPA_COMPLETED))) {
+ wpa_s->normal_scans = 0;
+ wpa_s->scan_req = 2;
+ 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 = 2;
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else {
@@ -3944,6 +4512,18 @@
} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
reply_len = wpa_supplicant_ctrl_iface_get_network(
wpa_s, buf + 12, reply, reply_size);
+ } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_list_creds(
+ wpa_s, reply, reply_size);
+ } else if (os_strcmp(buf, "ADD_CRED") == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_add_cred(
+ wpa_s, reply, reply_size);
+ } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
+ if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
+ if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
+ reply_len = -1;
#ifndef CONFIG_NO_CONFIG_WRITE
} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
@@ -3976,6 +4556,12 @@
} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
reply_size);
+ } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
+ if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
+ if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
+ reply_len = -1;
#endif /* CONFIG_AP */
} else if (os_strcmp(buf, "SUSPEND") == 0) {
wpas_notify_suspend(wpa_s->global);
@@ -4010,6 +4596,11 @@
} else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
reply_size);
+#ifdef CONFIG_AUTOSCAN
+ } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
+ if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
+ reply_len = -1;
+#endif /* CONFIG_AUTOSCAN */
#ifdef ANDROID
} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h
index 3f1c6a0..a329ef3 100644
--- a/wpa_supplicant/ctrl_iface.h
+++ b/wpa_supplicant/ctrl_iface.h
@@ -89,21 +89,6 @@
void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv);
/**
- * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
- * @wpa_s: Pointer to wpa_supplicant data
- * @ssid: Pointer to the network block the reply is for
- * @field: field the response is a reply for
- * @value: value (ie, password, etc) for @field
- * Returns: 0 on success, non-zero on error
- *
- * Helper function to handle replies to control interface requests.
- */
-int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- const char *field,
- const char *value);
-
-/**
* wpa_supplicant_global_ctrl_iface_init - Initialize global control interface
* @global: Pointer to global data from wpa_supplicant_init()
* Returns: Pointer to private data on success, %NULL on failure
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 301156e..8dba46d 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -184,6 +184,7 @@
wpa_s = eloop_ctx;
}
os_memmove(ifname, ifend, strlen(ifend) + 1);
+ wpa_printf(MSG_DEBUG, "wpa_s %p cmd %s", wpa_s, buf);
}
#endif /* defined CONFIG_P2P && defined ANDROID_P2P */
reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
@@ -397,7 +398,7 @@
}
if (bind(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ perror("supp-ctrl-iface-init: bind(PF_UNIX)");
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -689,7 +690,8 @@
os_strlcpy(addr.sun_path, global->params.ctrl_interface,
sizeof(addr.sun_path));
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ perror("supp-global-ctrl-iface-init (will try fixup): "
+ "bind(PF_UNIX)");
if (connect(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
@@ -704,7 +706,7 @@
}
if (bind(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ perror("supp-glb-iface-init: bind(PF_UNIX)");
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
diff --git a/wpa_supplicant/dbus/dbus_common.c b/wpa_supplicant/dbus/dbus_common.c
index 5850636..5d0e31e 100644
--- a/wpa_supplicant/dbus/dbus_common.c
+++ b/wpa_supplicant/dbus/dbus_common.c
@@ -4,14 +4,8 @@
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* 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/wpa_supplicant/dbus/dbus_common.h b/wpa_supplicant/dbus/dbus_common.h
index 50da09b..aea7db7 100644
--- a/wpa_supplicant/dbus/dbus_common.h
+++ b/wpa_supplicant/dbus/dbus_common.h
@@ -4,14 +4,8 @@
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* 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.
*/
#ifndef DBUS_COMMON_H
diff --git a/wpa_supplicant/dbus/dbus_common_i.h b/wpa_supplicant/dbus/dbus_common_i.h
index 9dab1ee..a551ccd 100644
--- a/wpa_supplicant/dbus/dbus_common_i.h
+++ b/wpa_supplicant/dbus/dbus_common_i.h
@@ -4,14 +4,8 @@
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* 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.
*/
#ifndef DBUS_COMMON_I_H
@@ -25,6 +19,10 @@
struct wpa_global *global;
u32 next_objid;
int dbus_new_initialized;
+
+#if defined(CONFIG_CTRL_IFACE_DBUS_NEW) && defined(CONFIG_AP)
+ int dbus_noc_refcnt;
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW && CONFIG_AP */
};
#endif /* DBUS_COMMON_I_H */
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index 68a9c28..67924e0 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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.
*/
#include "includes.h"
@@ -1104,5 +1098,5 @@
break;
}
- memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
+ os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
}
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index 2f6eb45..9666349 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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 DBUS_DICT_HELPERS_H
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index ce7cffb..a9957ab 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -4,14 +4,8 @@
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
* 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 "includes.h"
@@ -31,6 +25,99 @@
#include "dbus_new_handlers_p2p.h"
#include "p2p/p2p.h"
+#ifdef CONFIG_AP /* until needed by something else */
+
+/*
+ * NameOwnerChanged handling
+ *
+ * Some services we provide allow an application to register for
+ * a signal that it needs. While it can also unregister, we must
+ * be prepared for the case where the application simply crashes
+ * and thus doesn't clean up properly. The way to handle this in
+ * DBus is to register for the NameOwnerChanged signal which will
+ * signal an owner change to NULL if the peer closes the socket
+ * for whatever reason.
+ *
+ * Handle this signal via a filter function whenever necessary.
+ * The code below also handles refcounting in case in the future
+ * there will be multiple instances of this subscription scheme.
+ */
+static const char wpas_dbus_noc_filter_str[] =
+ "interface=org.freedesktop.DBus,member=NameOwnerChanged";
+
+
+static DBusHandlerResult noc_filter(DBusConnection *conn,
+ DBusMessage *message, void *data)
+{
+ struct wpas_dbus_priv *priv = data;
+
+ if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
+ "NameOwnerChanged")) {
+ const char *name;
+ const char *prev_owner;
+ const char *new_owner;
+ DBusError derr;
+ struct wpa_supplicant *wpa_s;
+
+ dbus_error_init(&derr);
+
+ if (!dbus_message_get_args(message, &derr,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &prev_owner,
+ DBUS_TYPE_STRING, &new_owner,
+ DBUS_TYPE_INVALID)) {
+ /* Ignore this error */
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ {
+ if (wpa_s->preq_notify_peer != NULL &&
+ os_strcmp(name, wpa_s->preq_notify_peer) == 0 &&
+ (new_owner == NULL || os_strlen(new_owner) == 0)) {
+ /* probe request owner disconnected */
+ os_free(wpa_s->preq_notify_peer);
+ wpa_s->preq_notify_peer = NULL;
+ wpas_dbus_unsubscribe_noc(priv);
+ }
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv)
+{
+ priv->dbus_noc_refcnt++;
+ if (priv->dbus_noc_refcnt > 1)
+ return;
+
+ if (!dbus_connection_add_filter(priv->con, noc_filter, priv, NULL)) {
+ wpa_printf(MSG_ERROR, "dbus: failed to add filter");
+ return;
+ }
+
+ dbus_bus_add_match(priv->con, wpas_dbus_noc_filter_str, NULL);
+}
+
+
+void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv)
+{
+ priv->dbus_noc_refcnt--;
+ if (priv->dbus_noc_refcnt > 0)
+ return;
+
+ dbus_bus_remove_match(priv->con, wpas_dbus_noc_filter_str, NULL);
+ dbus_connection_remove_filter(priv->con, noc_filter, priv);
+}
+
+#endif /* CONFIG_AP */
+
/**
* wpas_dbus_signal_interface - Send a interface related event signal
@@ -747,6 +834,41 @@
dbus_message_unref(msg);
}
+
+void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+ const char *status, const char *parameter)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "EAP");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status)
+ ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+ ¶meter))
+ goto nomem;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+ dbus_message_unref(msg);
+}
+
+
#ifdef CONFIG_P2P
/**
@@ -953,7 +1075,7 @@
if (os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN))
return -1;
- memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
+ os_memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
group_name[2] = '\0';
os_snprintf(group_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -1607,10 +1729,12 @@
enum wpas_dbus_prop property)
{
char *prop;
+ dbus_bool_t flush;
if (wpa_s->dbus_new_path == NULL)
return; /* Skip signal since D-Bus setup is not yet ready */
+ flush = FALSE;
switch (property) {
case WPAS_DBUS_PROP_AP_SCAN:
prop = "ApScan";
@@ -1633,6 +1757,10 @@
case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
prop = "CurrentAuthMode";
break;
+ case WPAS_DBUS_PROP_DISCONNECT_REASON:
+ prop = "DisconnectReason";
+ flush = TRUE;
+ break;
default:
wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
__func__, property);
@@ -1642,6 +1770,10 @@
wpa_dbus_mark_property_changed(wpa_s->global->dbus,
wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_INTERFACE, prop);
+ if (flush) {
+ wpa_dbus_flush_object_changed_properties(
+ wpa_s->global->dbus->con, wpa_s->dbus_new_path);
+ }
}
@@ -1792,6 +1924,15 @@
END_ARGS
}
},
+#ifdef CONFIG_AUTOSCAN
+ { "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
+ {
+ { "arg", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_AUTOSCAN */
{ NULL, NULL, NULL, { END_ARGS } }
};
@@ -2029,11 +2170,11 @@
struct wpas_dbus_priv *ctrl_iface;
char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
int ret;
+#ifdef CONFIG_P2P
struct wpa_ssid *ssid;
ssid = wpa_config_get_network(wpa_s->conf, nid);
-#ifdef CONFIG_P2P
/* If it is a persistent group unregister it as such */
if (ssid && network_is_persistent_group(ssid))
return wpas_dbus_unregister_persistent_group(wpa_s, nid);
@@ -2487,6 +2628,20 @@
END_ARGS
}
},
+#ifdef CONFIG_AP
+ { "SubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_subscribe_preq,
+ {
+ END_ARGS
+ }
+ },
+ { "UnsubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_unsubscribe_preq,
+ {
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_AP */
{ NULL, NULL, NULL, { END_ARGS } }
};
@@ -2559,6 +2714,10 @@
wpas_dbus_getter_fast_reauth,
wpas_dbus_setter_fast_reauth
},
+ { "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+ wpas_dbus_getter_scan_interval,
+ wpas_dbus_setter_scan_interval
+ },
#ifdef CONFIG_WPS
{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
wpas_dbus_getter_process_credentials,
@@ -2566,9 +2725,9 @@
},
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
- { "P2PDeviceProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
- wpas_dbus_getter_p2p_device_properties,
- wpas_dbus_setter_p2p_device_properties
+ { "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
+ wpas_dbus_getter_p2p_device_config,
+ wpas_dbus_setter_p2p_device_config
},
{ "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
wpas_dbus_getter_p2p_peers,
@@ -2591,6 +2750,10 @@
NULL
},
#endif /* CONFIG_P2P */
+ { "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+ wpas_dbus_getter_disconnect_reason,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL }
};
@@ -2809,12 +2972,27 @@
}
},
#endif /* CONFIG_P2P */
+#ifdef CONFIG_AP
+ { "ProbeRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_AP */
{ "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE,
{
{ "certification", "a{sv}", ARG_OUT },
END_ARGS
}
},
+ { "EAP", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "status", "s", ARG_OUT },
+ { "parameter", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
{ NULL, NULL, { END_ARGS } }
};
@@ -2882,6 +3060,15 @@
wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
wpa_s->dbus_new_path);
+
+#ifdef CONFIG_AP
+ if (wpa_s->preq_notify_peer) {
+ wpas_dbus_unsubscribe_noc(ctrl_iface);
+ os_free(wpa_s->preq_notify_peer);
+ wpa_s->preq_notify_peer = NULL;
+ }
+#endif /* CONFIG_AP */
+
if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
wpa_s->dbus_new_path))
return -1;
@@ -2921,11 +3108,11 @@
wpas_dbus_getter_p2p_peer_group_capability,
NULL
},
- { "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+ { "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
wpas_dbus_getter_p2p_peer_secondary_device_types,
NULL
},
- { "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "as",
+ { "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
wpas_dbus_getter_p2p_peer_vendor_extension,
NULL
},
@@ -3126,10 +3313,37 @@
wpas_dbus_getter_p2p_group_members,
NULL
},
- { "Properties",
- WPAS_DBUS_NEW_IFACE_P2P_GROUP, "a{sv}",
- wpas_dbus_getter_p2p_group_properties,
- wpas_dbus_setter_p2p_group_properties
+ { "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o",
+ wpas_dbus_getter_p2p_group,
+ NULL
+ },
+ { "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
+ wpas_dbus_getter_p2p_role,
+ NULL
+ },
+ { "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
+ wpas_dbus_getter_p2p_group_ssid,
+ NULL
+ },
+ { "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
+ wpas_dbus_getter_p2p_group_bssid,
+ NULL
+ },
+ { "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q",
+ wpas_dbus_getter_p2p_group_frequency,
+ NULL
+ },
+ { "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
+ wpas_dbus_getter_p2p_group_passphrase,
+ NULL
+ },
+ { "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
+ wpas_dbus_getter_p2p_group_psk,
+ NULL
+ },
+ { "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay",
+ wpas_dbus_getter_p2p_group_vendor_ext,
+ wpas_dbus_setter_p2p_group_vendor_ext
},
{ NULL, NULL, NULL, NULL, NULL }
};
@@ -3251,10 +3465,6 @@
static const struct wpa_dbus_property_desc
wpas_dbus_p2p_groupmember_properties[] = {
- { "Properties", WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER, "a{sv}",
- wpas_dbus_getter_p2p_group_properties,
- NULL
- },
{ NULL, NULL, NULL, NULL, NULL }
};
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 93ce722..44cde42 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -3,14 +3,8 @@
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
*
- * 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 CTRL_IFACE_DBUS_NEW_H
@@ -34,6 +28,7 @@
WPAS_DBUS_PROP_CURRENT_NETWORK,
WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
WPAS_DBUS_PROP_BSSS,
+ WPAS_DBUS_PROP_DISCONNECT_REASON,
};
enum wpas_dbus_bss_prop {
@@ -115,6 +110,17 @@
#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
WPAS_DBUS_NEW_INTERFACE ".BlobUnknown"
+#define WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE \
+ WPAS_DBUS_NEW_INTERFACE ".SubscriptionInUse"
+#define WPAS_DBUS_ERROR_NO_SUBSCRIPTION \
+ WPAS_DBUS_NEW_INTERFACE ".NoSubscription"
+#define WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM \
+ WPAS_DBUS_NEW_INTERFACE ".SubscriptionNotYou"
+
+
+void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv);
+void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv);
+
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
@@ -210,6 +216,11 @@
int depth, const char *subject,
const char *cert_hash,
const struct wpabuf *cert);
+void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len, u32 ssi_signal);
+void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+ const char *status, const char *parameter);
#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
@@ -467,6 +478,20 @@
{
}
+static inline void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst,
+ const u8 *bssid,
+ const u8 *ie, size_t ie_len,
+ u32 ssi_signal)
+{
+}
+
+static inline void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+ const char *status,
+ const char *parameter)
+{
+}
+
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
#endif /* CTRL_IFACE_DBUS_H_NEW */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index da67bea..8145a70 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -4,14 +4,8 @@
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
* 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 "includes.h"
@@ -28,10 +22,12 @@
#include "../bss.h"
#include "../scan.h"
#include "../ctrl_iface.h"
+#include "../autoscan.h"
#include "dbus_new_helpers.h"
#include "dbus_new.h"
#include "dbus_new_handlers.h"
#include "dbus_dict_helpers.h"
+#include "dbus_common_i.h"
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
@@ -253,7 +249,7 @@
if ((os_strcmp(entry.key, "psk") == 0 &&
value[0] == '"' && ssid->ssid_len) ||
- (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
+ (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
wpa_config_update_psk(ssid);
else if (os_strcmp(entry.key, "priority") == 0)
wpa_config_update_prio_list(wpa_s->conf);
@@ -448,6 +444,76 @@
/**
+ * wpas_dbus_simple_array_array_property_getter - Get array array type property
+ * @iter: Pointer to incoming dbus message iterator
+ * @type: DBus type of property array elements (must be basic type)
+ * @array: pointer to array of elements to put into response message
+ * @array_len: length of above array
+ * @error: a pointer to an error to fill on failure
+ * Returns: TRUE if the request succeeded, FALSE if it failed
+ *
+ * Generic getter for array type properties. Array elements type is
+ * required to be basic.
+ */
+dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
+ const int type,
+ struct wpabuf **array,
+ size_t array_len,
+ DBusError *error)
+{
+ DBusMessageIter variant_iter, array_iter;
+ char type_str[] = "aa?";
+ char inner_type_str[] = "a?";
+ const char *sub_type_str;
+ size_t i;
+
+ if (!dbus_type_is_basic(type)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: given type is not basic", __func__);
+ return FALSE;
+ }
+
+ sub_type_str = wpa_dbus_type_as_string(type);
+ type_str[2] = sub_type_str[0];
+ inner_type_str[1] = sub_type_str[0];
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ type_str, &variant_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct message 1", __func__);
+ return FALSE;
+ }
+ if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ inner_type_str, &array_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct message 2", __func__);
+ return FALSE;
+ }
+
+ for (i = 0; i < array_len; i++) {
+ wpa_dbus_dict_bin_array_add_element(&array_iter,
+ wpabuf_head(array[i]),
+ wpabuf_len(array[i]));
+
+ }
+
+ if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to close message 2", __func__);
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to close message 1", __func__);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
* wpas_dbus_handler_create_interface - Request registration of a network iface
* @message: Pointer to incoming dbus message
* @global: %wpa_supplicant global data structure
@@ -477,25 +543,25 @@
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!strcmp(entry.key, "Driver") &&
+ if (!os_strcmp(entry.key, "Driver") &&
(entry.type == DBUS_TYPE_STRING)) {
driver = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (driver == NULL)
goto error;
- } else if (!strcmp(entry.key, "Ifname") &&
+ } else if (!os_strcmp(entry.key, "Ifname") &&
(entry.type == DBUS_TYPE_STRING)) {
ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (ifname == NULL)
goto error;
- } else if (!strcmp(entry.key, "ConfigFile") &&
+ } else if (!os_strcmp(entry.key, "ConfigFile") &&
(entry.type == DBUS_TYPE_STRING)) {
confname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (confname == NULL)
goto error;
- } else if (!strcmp(entry.key, "BridgeIfname") &&
+ } else if (!os_strcmp(entry.key, "BridgeIfname") &&
(entry.type == DBUS_TYPE_STRING)) {
bridge_ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
@@ -1216,6 +1282,9 @@
/* Add wildcard ssid */
params.num_ssids++;
}
+#ifdef CONFIG_AUTOSCAN
+ autoscan_deinit(wpa_s);
+#endif /* CONFIG_AUTOSCAN */
wpa_supplicant_trigger_scan(wpa_s, ¶ms);
} else {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
@@ -1736,6 +1805,54 @@
}
+#ifdef CONFIG_AUTOSCAN
+/**
+ * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "AutoScan" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ enum wpa_states state = wpa_s->wpa_state;
+ char *arg;
+
+ dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
+ DBUS_TYPE_INVALID);
+
+ if (arg != NULL && os_strlen(arg) > 0) {
+ char *tmp;
+ tmp = os_strdup(arg);
+ if (tmp == NULL) {
+ reply = dbus_message_new_error(message,
+ DBUS_ERROR_NO_MEMORY,
+ NULL);
+ } else {
+ os_free(wpa_s->conf->autoscan);
+ wpa_s->conf->autoscan = tmp;
+ if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+ autoscan_init(wpa_s, 1);
+ else if (state == WPA_SCANNING)
+ wpa_supplicant_reinit_autoscan(wpa_s);
+ }
+ } else if (arg != NULL && os_strlen(arg) == 0) {
+ os_free(wpa_s->conf->autoscan);
+ wpa_s->conf->autoscan = NULL;
+ autoscan_deinit(wpa_s);
+ } else
+ reply = dbus_message_new_error(message,
+ DBUS_ERROR_INVALID_ARGS,
+ NULL);
+
+ return reply;
+}
+#endif /* CONFIG_AUTOSCAN */
+
+
/**
* wpas_dbus_getter_capabilities - Return interface capabilities
* @iter: Pointer to incoming dbus message iter
@@ -2229,6 +2346,27 @@
/**
+ * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "DisconnectReason" property. The reason is negative if it is
+ * locally generated.
+ */
+dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_int32_t reason = wpa_s->disconnect_reason;
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+ &reason, error);
+}
+
+
+/**
* wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -2392,6 +2530,56 @@
/**
+ * wpas_dbus_getter_scan_interval - Get scan interval
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter function for "ScanInterval" property.
+ */
+dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_int32_t scan_interval = wpa_s->scan_interval;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+ &scan_interval, error);
+}
+
+
+/**
+ * wpas_dbus_setter_scan_interval - Control scan interval
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "ScanInterval" property.
+ */
+dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_int32_t scan_interval;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
+ &scan_interval))
+ return FALSE;
+
+ if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
+ dbus_set_error_const(error, DBUS_ERROR_FAILED,
+ "scan_interval must be >= 0");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/**
* wpas_dbus_getter_ifname - Get interface name
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -3292,3 +3480,139 @@
dbus_message_iter_recurse(iter, &variant_iter);
return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
}
+
+
+#ifdef CONFIG_AP
+
+DBusMessage * wpas_dbus_handler_subscribe_preq(
+ DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+ char *name;
+
+ if (wpa_s->preq_notify_peer != NULL) {
+ if (os_strcmp(dbus_message_get_sender(message),
+ wpa_s->preq_notify_peer) == 0)
+ return NULL;
+
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
+ "Another application is already subscribed");
+ }
+
+ name = os_strdup(dbus_message_get_sender(message));
+ if (!name)
+ return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+ "out of memory");
+
+ wpa_s->preq_notify_peer = name;
+
+ /* Subscribe to clean up if application closes socket */
+ wpas_dbus_subscribe_noc(priv);
+
+ /*
+ * Double-check it's still alive to make sure that we didn't
+ * miss the NameOwnerChanged signal, e.g. while strdup'ing.
+ */
+ if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
+ /*
+ * Application no longer exists, clean up.
+ * The return value is irrelevant now.
+ *
+ * Need to check if the NameOwnerChanged handling
+ * already cleaned up because we have processed
+ * DBus messages while checking if the name still
+ * has an owner.
+ */
+ if (!wpa_s->preq_notify_peer)
+ return NULL;
+ os_free(wpa_s->preq_notify_peer);
+ wpa_s->preq_notify_peer = NULL;
+ wpas_dbus_unsubscribe_noc(priv);
+ }
+
+ return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_unsubscribe_preq(
+ DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+
+ if (!wpa_s->preq_notify_peer)
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
+ "Not subscribed");
+
+ if (os_strcmp(wpa_s->preq_notify_peer,
+ dbus_message_get_sender(message)))
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
+ "Can't unsubscribe others");
+
+ os_free(wpa_s->preq_notify_peer);
+ wpa_s->preq_notify_peer = NULL;
+ wpas_dbus_unsubscribe_noc(priv);
+ return NULL;
+}
+
+
+void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len, u32 ssi_signal)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (priv == NULL)
+ return;
+
+ if (wpa_s->preq_notify_peer == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "ProbeRequest");
+ if (msg == NULL)
+ return;
+
+ dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto fail;
+ if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
+ (const char *) addr,
+ ETH_ALEN))
+ goto fail;
+ if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
+ (const char *) dst,
+ ETH_ALEN))
+ goto fail;
+ if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
+ (const char *) bssid,
+ ETH_ALEN))
+ goto fail;
+ if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
+ (const char *) ie,
+ ie_len))
+ goto fail;
+ if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
+ ssi_signal))
+ goto fail;
+ if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto fail;
+
+ dbus_connection_send(priv->con, msg, NULL);
+ goto out;
+fail:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+out:
+ dbus_message_unref(msg);
+}
+
+#endif /* CONFIG_AP */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index c0272d5..cff218f 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -3,14 +3,8 @@
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
*
- * 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 CTRL_IFACE_DBUS_NEW_HANDLERS_H
@@ -41,6 +35,12 @@
size_t array_len,
DBusError *error);
+dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
+ const int type,
+ struct wpabuf **array,
+ size_t array_len,
+ DBusError *error);
+
DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
struct wpa_global *global);
@@ -118,6 +118,9 @@
DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
DBusError *error, void *user_data);
@@ -141,6 +144,10 @@
DBusError *error,
void *user_data);
+dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
+
dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
DBusError *error, void *user_data);
@@ -162,6 +169,14 @@
dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
void *user_data);
+dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
+
+dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
+
dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
void *user_data);
@@ -252,4 +267,9 @@
DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
const char *arg);
+DBusMessage * wpas_dbus_handler_subscribe_preq(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_unsubscribe_preq(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
#endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 79373b4..f4541f7 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -1,14 +1,9 @@
/*
* WPA Supplicant / dbus-based control interface (P2P)
+ * Copyright (c) 2011-2012, 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 "includes.h"
@@ -45,7 +40,7 @@
if (!peer_path)
return -1;
- p = strrchr(peer_path, '/');
+ p = os_strrchr(peer_path, '/');
if (!p)
return -1;
p++;
@@ -508,8 +503,8 @@
goto inv_args;
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
- persistent_group, join, authorize_only,
- go_intent, freq);
+ persistent_group, 0, join, authorize_only,
+ go_intent, freq, -1, 0);
if (new_pin >= 0) {
char npin[9];
@@ -692,7 +687,8 @@
os_strcmp(config_method, "pushbutton"))
return wpas_dbus_error_invalid_args(message, NULL);
- if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, 0) < 0)
+ if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
+ WPAS_P2P_PD_FOR_GO_NEG) < 0)
return wpas_dbus_error_unknown_error(message,
"Failed to send provision discovery request");
@@ -704,9 +700,9 @@
* P2P Device property accessor methods.
*/
-dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
DBusMessageIter variant_iter, dict_iter;
@@ -782,7 +778,7 @@
goto err_no_mem;
/* Persistent Reconnect */
- if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
+ if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
wpa_s->conf->persistent_reconnect))
goto err_no_mem;
@@ -839,9 +835,9 @@
}
-dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
DBusMessageIter variant_iter, iter_dict;
@@ -927,7 +923,7 @@
(entry.type == DBUS_TYPE_UINT32) &&
(entry.uint32_value <= 15))
wpa_s->conf->p2p_go_intent = entry.uint32_value;
- else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
+ else if ((os_strcmp(entry.key, "PersistentReconnect") == 0) &&
(entry.type == DBUS_TYPE_BOOLEAN))
wpa_s->conf->persistent_reconnect = entry.bool_value;
else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
@@ -1140,13 +1136,18 @@
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
+ char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
+ char *dbus_groupobj_path = path_buf;
if (wpa_s->dbus_groupobj_path == NULL)
- return FALSE;
+ os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "/");
+ else
+ os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s", wpa_s->dbus_groupobj_path);
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
- &wpa_s->dbus_groupobj_path,
- error);
+ &dbus_groupobj_path, error);
}
@@ -1157,11 +1158,13 @@
char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
- return FALSE;
+ os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
+ else
+ os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+ COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
- os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
- wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
path = go_peer_obj_path;
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
&path, error);
@@ -1341,6 +1344,7 @@
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
+ DBusMessageIter variant_iter, array_iter;
info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
peer_args->p2p_device_addr, 0);
@@ -1350,29 +1354,80 @@
return FALSE;
}
- if (info->wps_sec_dev_type_list_len) {
- const u8 *sec_dev_type_list = info->wps_sec_dev_type_list;
- int num_sec_dev_types = info->wps_sec_dev_type_list_len;
-
- if (!wpas_dbus_simple_array_property_getter(iter,
- DBUS_TYPE_BYTE,
- sec_dev_type_list,
- num_sec_dev_types,
- error))
- goto err_no_mem;
- else
- return TRUE;
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING,
+ &variant_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct message 1", __func__);
+ return FALSE;
}
- if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, NULL,
- 0, error))
- goto err_no_mem;
+ if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING,
+ &array_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct message 2", __func__);
+ return FALSE;
+ }
+
+ if (info->wps_sec_dev_type_list_len) {
+ const u8 *sec_dev_type_list = info->wps_sec_dev_type_list;
+ int num_sec_device_types =
+ info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN;
+ int i;
+ DBusMessageIter inner_array_iter;
+
+ for (i = 0; i < num_sec_device_types; i++) {
+ if (!dbus_message_iter_open_container(
+ &array_iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &inner_array_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct "
+ "message 3 (%d)",
+ __func__, i);
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_append_fixed_array(
+ &inner_array_iter, DBUS_TYPE_BYTE,
+ &sec_dev_type_list, WPS_DEV_TYPE_LEN)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct "
+ "message 4 (%d)",
+ __func__, i);
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_close_container(
+ &array_iter, &inner_array_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct "
+ "message 5 (%d)",
+ __func__, i);
+ return FALSE;
+ }
+
+ sec_dev_type_list += WPS_DEV_TYPE_LEN;
+ }
+ }
+
+ if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct message 6", __func__);
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to construct message 7", __func__);
+ return FALSE;
+ }
return TRUE;
-
-err_no_mem:
- dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
- return FALSE;
}
@@ -1380,7 +1435,7 @@
DBusError *error,
void *user_data)
{
- const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
+ struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
int i, num;
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1401,12 +1456,10 @@
num++;
}
- if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_STRING,
- vendor_extension, num,
- error)) {
- dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE,
+ vendor_extension,
+ num, error))
return FALSE;
- }
return TRUE;
}
@@ -1415,10 +1468,12 @@
dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
DBusError *error, void *user_data)
{
+ dbus_bool_t success;
/* struct peer_handler_args *peer_args = user_data; */
- dbus_set_error_const(error, DBUS_ERROR_FAILED, "not implemented");
- return FALSE;
+ success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ NULL, 0, error);
+ return success;
}
@@ -1746,9 +1801,11 @@
const u8 *addr;
dbus_bool_t success = FALSE;
- /* Ensure we are a GO */
- if (wpa_s->wpa_state != WPA_COMPLETED)
- return FALSE;
+ /* Verify correct role for this property */
+ if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_GO) {
+ return wpas_dbus_simple_array_property_getter(
+ iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
+ }
ssid = wpa_s->conf->ssid;
/* At present WPAS P2P_GO mode only applicable for p2p_go */
@@ -1796,111 +1853,145 @@
}
-dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
+dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
+ DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ if (wpa_s->current_ssid == NULL)
+ return FALSE;
+ return wpas_dbus_simple_array_property_getter(
+ iter, DBUS_TYPE_BYTE, wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len, error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ u8 role = wpas_get_p2p_role(wpa_s);
+ u8 *p_bssid;
+
+ if (role == WPAS_P2P_ROLE_CLIENT) {
+ if (wpa_s->current_ssid == NULL)
+ return FALSE;
+ p_bssid = wpa_s->current_ssid->bssid;
+ } else {
+ if (wpa_s->ap_iface == NULL)
+ return FALSE;
+ p_bssid = wpa_s->ap_iface->bss[0]->own_addr;
+ }
+
+ return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ p_bssid, ETH_ALEN,
+ error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ u16 op_freq;
+ u8 role = wpas_get_p2p_role(wpa_s);
+
+ if (role == WPAS_P2P_ROLE_CLIENT) {
+ if (wpa_s->go_params == NULL)
+ return FALSE;
+ op_freq = wpa_s->go_params->freq;
+ } else {
+ if (wpa_s->ap_iface == NULL)
+ return FALSE;
+ op_freq = wpa_s->ap_iface->freq;
+ }
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+ &op_freq, error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- DBusMessageIter variant_iter, dict_iter;
- struct hostapd_data *hapd = NULL;
- const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
- int num_vendor_ext = 0;
- int i;
u8 role = wpas_get_p2p_role(wpa_s);
- u16 op_freq = 0;
- u8 *p_bssid = NULL;
- char *role_name = NULL;
+ char *p_pass = NULL;
- if (!wpa_s->current_ssid)
- return FALSE;
-
- /* Check current role and adjust information accordingly */
- switch (role) {
- case WPAS_P2P_ROLE_CLIENT:
- /* go_params is only valid for a client */
- if (wpa_s->go_params) {
- op_freq = wpa_s->go_params->freq;
- p_bssid = wpa_s->current_ssid->bssid;
- role_name = "client";
- } else
- return FALSE;
- break;
- case WPAS_P2P_ROLE_GO:
- /* ap_iface is only valid for a GO */
- if (wpa_s->ap_iface) {
- hapd = wpa_s->ap_iface->bss[0];
- p_bssid = hapd->own_addr;
- op_freq = wpa_s->ap_iface->freq;
- role_name = "GO";
- } else
- return FALSE;
- break;
- default:
- /* Error condition; this should NEVER occur */
- return FALSE;
- }
-
- if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- "a{sv}", &variant_iter) ||
- !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
- goto err_no_mem;
- /* Provide the SSID */
- if (!wpa_dbus_dict_append_byte_array(
- &dict_iter, "SSID",
- (const char *) wpa_s->current_ssid->ssid,
- wpa_s->current_ssid->ssid_len))
- goto err_no_mem;
- /* Provide the BSSID */
- if (p_bssid &&
- !wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
- (const char *) p_bssid, ETH_ALEN))
- goto err_no_mem;
- /* Provide the role within the group */
- if (role_name &&
- !wpa_dbus_dict_append_string(&dict_iter, "Role", role_name))
- goto err_no_mem;
- /* Provide the operational frequency */
- if (!wpa_dbus_dict_append_uint16(&dict_iter, "Frequency", op_freq))
- goto err_no_mem;
-
- /* Additional information for group owners */
+ /* Verify correct role for this property */
if (role == WPAS_P2P_ROLE_GO) {
- /* Provide the passphrase */
- if (!wpa_dbus_dict_append_string(&dict_iter, "Passphrase",
- wpa_s->current_ssid->passphrase))
- goto err_no_mem;
- /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
- for (i = 0; hapd && i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
- if (hapd->conf->wps_vendor_ext[i] == NULL)
- continue;
- vendor_ext[num_vendor_ext++] =
- hapd->conf->wps_vendor_ext[i];
- }
- if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
- "WPSVendorExtensions",
- vendor_ext, num_vendor_ext))
- goto err_no_mem;
- } else {
- /* If not a GO, provide the PSK */
- if (!wpa_dbus_dict_append_byte_array(
- &dict_iter, "PSK",
- (const char *) wpa_s->current_ssid->psk, 32))
- goto err_no_mem;
- }
+ if (wpa_s->current_ssid == NULL)
+ return FALSE;
+ p_pass = wpa_s->current_ssid->passphrase;
+ } else
+ p_pass = "";
- if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
- !dbus_message_iter_close_container(iter, &variant_iter))
- goto err_no_mem;
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+ &p_pass, error);
- return TRUE;
-
-err_no_mem:
- dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
- return FALSE;
}
-dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
+dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
+ DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ u8 role = wpas_get_p2p_role(wpa_s);
+ u8 *p_psk = NULL;
+ u8 psk_len = 0;
+
+ /* Verify correct role for this property */
+ if (role == WPAS_P2P_ROLE_CLIENT) {
+ if (wpa_s->current_ssid == NULL)
+ return FALSE;
+ p_psk = wpa_s->current_ssid->psk;
+ psk_len = 32;
+ }
+
+ return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ &p_psk, psk_len, error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ struct hostapd_data *hapd;
+ struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ int num_vendor_ext = 0;
+ int i;
+
+ /* Verify correct role for this property */
+ if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) {
+ if (wpa_s->ap_iface == NULL)
+ return FALSE;
+ hapd = wpa_s->ap_iface->bss[0];
+
+ /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+ if (hapd->conf->wps_vendor_ext[i] == NULL)
+ vendor_ext[i] = NULL;
+ else {
+ vendor_ext[num_vendor_ext++] =
+ hapd->conf->wps_vendor_ext[i];
+ }
+ }
+ }
+
+ /* Return vendor extensions or no data */
+ return wpas_dbus_simple_array_array_property_getter(iter,
+ DBUS_TYPE_BYTE,
+ vendor_ext,
+ num_vendor_ext,
+ error);
+}
+
+
+dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
DBusError *error,
void *user_data)
{
@@ -1978,7 +2069,7 @@
if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
goto error;
- if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
@@ -1990,23 +2081,30 @@
bonjour = 1;
else
goto error_clear;
- wpa_dbus_dict_entry_clear(&entry);
+ } else if (!os_strcmp(entry.key, "version") &&
+ entry.type == DBUS_TYPE_INT32) {
+ version = entry.uint32_value;
+ } else if (!os_strcmp(entry.key, "service") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ service = os_strdup(entry.str_value);
+ } else if (!os_strcmp(entry.key, "query")) {
+ if ((entry.type != DBUS_TYPE_ARRAY) ||
+ (entry.array_type != DBUS_TYPE_BYTE))
+ goto error_clear;
+ query = wpabuf_alloc_copy(
+ entry.bytearray_value,
+ entry.array_len);
+ } else if (!os_strcmp(entry.key, "response")) {
+ if ((entry.type != DBUS_TYPE_ARRAY) ||
+ (entry.array_type != DBUS_TYPE_BYTE))
+ goto error_clear;
+ resp = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
}
+ wpa_dbus_dict_entry_clear(&entry);
}
if (upnp == 1) {
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
-
- if (!os_strcmp(entry.key, "version") &&
- entry.type == DBUS_TYPE_INT32)
- version = entry.uint32_value;
- else if (!os_strcmp(entry.key, "service") &&
- entry.type == DBUS_TYPE_STRING)
- service = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- }
if (version <= 0 || service == NULL)
goto error;
@@ -2014,37 +2112,15 @@
goto error;
os_free(service);
+ service = NULL;
} else if (bonjour == 1) {
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
-
- if (!os_strcmp(entry.key, "query")) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != DBUS_TYPE_BYTE))
- goto error_clear;
- query = wpabuf_alloc_copy(
- entry.bytearray_value,
- entry.array_len);
- } else if (!os_strcmp(entry.key, "response")) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != DBUS_TYPE_BYTE))
- goto error_clear;
- resp = wpabuf_alloc_copy(entry.bytearray_value,
- entry.array_len);
- }
-
- wpa_dbus_dict_entry_clear(&entry);
- }
-
if (query == NULL || resp == NULL)
goto error;
- if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
- wpabuf_free(query);
- wpabuf_free(resp);
+ if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0)
goto error;
- }
+ query = NULL;
+ resp = NULL;
} else
goto error;
@@ -2052,6 +2128,9 @@
error_clear:
wpa_dbus_dict_entry_clear(&entry);
error:
+ os_free(service);
+ wpabuf_free(query);
+ wpabuf_free(resp);
return wpas_dbus_error_invalid_args(message, NULL);
}
@@ -2170,7 +2249,7 @@
struct wpabuf *tlv = NULL;
u8 version = 0;
u64 ref = 0;
- u8 addr[ETH_ALEN];
+ u8 addr_buf[ETH_ALEN], *addr;
dbus_message_iter_init(message, &iter);
@@ -2207,10 +2286,15 @@
wpa_dbus_dict_entry_clear(&entry);
}
- if (!peer_object_path ||
- (parse_peer_object_path(peer_object_path, addr) < 0) ||
- !p2p_peer_known(wpa_s->global->p2p, addr))
- goto error;
+ if (!peer_object_path) {
+ addr = NULL;
+ } else {
+ if (parse_peer_object_path(peer_object_path, addr_buf) < 0 ||
+ !p2p_peer_known(wpa_s->global->p2p, addr_buf))
+ goto error;
+
+ addr = addr_buf;
+ }
if (upnp == 1) {
if (version <= 0 || service == NULL)
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index 293eb6b..a11b3c8 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -1,15 +1,9 @@
-
/*
* WPA Supplicant / dbus-based control interface for p2p
+ * Copyright (c) 2011-2012, 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.
*/
#ifndef DBUS_NEW_HANDLERS_P2P_H
@@ -94,13 +88,13 @@
/*
* P2P Device property accessor methods.
*/
-dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
-dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
void *user_data);
@@ -161,11 +155,31 @@
DBusError *error,
void *user_data);
-dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
+dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
DBusError *error,
void *user_data);
-dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
+dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
+
+dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
DBusError *error,
void *user_data);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index a72cfb3..8489ce7 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -3,14 +3,8 @@
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
*
- * 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 "includes.h"
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index e254365..cfa6a15 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -3,14 +3,8 @@
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
*
- * 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/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h
index d6e7b48..6d31ad5 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -3,14 +3,8 @@
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
*
- * 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 WPA_DBUS_CTRL_H
diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c
index d443269..3b090c0 100644
--- a/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -4,14 +4,8 @@
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 2010, 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/wpa_supplicant/dbus/dbus_old.c b/wpa_supplicant/dbus/dbus_old.c
index 71ab61e..5f298e7 100644
--- a/wpa_supplicant/dbus/dbus_old.c
+++ b/wpa_supplicant/dbus/dbus_old.c
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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.
*/
#include "includes.h"
diff --git a/wpa_supplicant/dbus/dbus_old.h b/wpa_supplicant/dbus/dbus_old.h
index 9523867..e668231 100644
--- a/wpa_supplicant/dbus/dbus_old.h
+++ b/wpa_supplicant/dbus/dbus_old.h
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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 CTRL_IFACE_DBUS_H
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index 8370a95..e217a72 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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.
*/
#include "includes.h"
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.h b/wpa_supplicant/dbus/dbus_old_handlers.h
index 009e807..825bc6d 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.h
+++ b/wpa_supplicant/dbus/dbus_old_handlers.h
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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 CTRL_IFACE_DBUS_HANDLERS_H
diff --git a/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
index c04b844..bb79382 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
@@ -2,14 +2,8 @@
* WPA Supplicant / dbus-based control interface (WPS)
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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.
*/
#include "includes.h"
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 480bc64..fe1401f 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -204,6 +204,8 @@
# Disable credentials for an open network by default when acting as a WPS
# registrar.
#CONFIG_WPS_REG_DISABLE_OPEN=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
@@ -321,9 +323,7 @@
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
CONFIG_PEERKEY=y
-# IEEE 802.11w (management frame protection)
-# This version is an experimental implementation based on IEEE 802.11w/D1.0
-# draft and is subject to change since the standard has not yet been finalized.
+# IEEE 802.11w (management frame protection), also known as PMF
# Driver support is also needed for IEEE 802.11w.
#CONFIG_IEEE80211W=y
@@ -413,6 +413,12 @@
# Set syslog facility for debug messages
#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
# Enable privilege separation (see README 'Privilege separation' for details)
#CONFIG_PRIVSEP=y
@@ -424,7 +430,7 @@
# This tracks use of memory allocations and other registrations and reports
# incorrect use with a backtrace of call (or allocation) location.
#CONFIG_WPA_TRACE=y
-# For BSD, comment out these.
+# For BSD, uncomment these.
#LIBS += -lexecinfo
#LIBS_p += -lexecinfo
#LIBS_c += -lexecinfo
@@ -433,7 +439,7 @@
# This enables use of libbfd to get more detailed symbols for the backtraces
# generated by CONFIG_WPA_TRACE=y.
#CONFIG_WPA_TRACE_BFD=y
-# For BSD, comment out these.
+# For BSD, uncomment these.
#LIBS += -lbfd -liberty -lz
#LIBS_p += -lbfd -liberty -lz
#LIBS_c += -lbfd -liberty -lz
@@ -472,8 +478,37 @@
# IEEE 802.11n (High Throughput) support (mainly for AP mode)
#CONFIG_IEEE80211N=y
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
# Interworking (IEEE 802.11u)
# This can be used to enable functionality to improve interworking with
# external networks (GAS/ANQP to learn more about the networks and network
# selection based on available credentials).
#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
+#CONFIG_AP=y
+
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+#CONFIG_P2P=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+#CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml
index f47235b..eb3a089 100644
--- a/wpa_supplicant/doc/docbook/wpa_background.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -90,12 +90,12 @@
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2012,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml
index 1fe98f4..c080c07 100644
--- a/wpa_supplicant/doc/docbook/wpa_cli.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -328,12 +328,12 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2012,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml
index 41b5849..0ab6419 100644
--- a/wpa_supplicant/doc/docbook/wpa_gui.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml
@@ -74,12 +74,12 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2012,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
index 402ea09..336c03b 100644
--- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -62,12 +62,12 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2012,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml
index 89b8a92..eb907a8 100644
--- a/wpa_supplicant/doc/docbook/wpa_priv.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml
@@ -137,12 +137,12 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2012,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 0ab4e15..aa20e57 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -246,28 +246,6 @@
<variablelist>
<varlistentry>
- <term>hostap</term>
- <listitem>
- <para>(default) Host AP driver (Intersil Prism2/2.5/3).
- (this can also be used with Linuxant DriverLoader).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>hermes</term>
- <listitem>
- <para>Agere Systems Inc. driver (Hermes-I/Hermes-II).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>madwifi</term>
- <listitem>
- <para>MADWIFI 802.11 support (Atheros, etc.).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term>wext</term>
<listitem>
<para>Linux wireless extensions (generic).</para>
@@ -275,13 +253,6 @@
</varlistentry>
<varlistentry>
- <term>broadcom</term>
- <listitem>
- <para>Broadcom wl.o driver.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term>wired</term>
<listitem>
<para>wpa_supplicant wired Ethernet driver</para>
@@ -411,7 +382,7 @@
<varlistentry>
<term>-L</term>
<listitem>
- <para>Show license (GPL and BSD).</para>
+ <para>Show license (BSD).</para>
</listitem>
</varlistentry>
@@ -506,8 +477,8 @@
<blockquote><programlisting>
wpa_supplicant \
- -c wpa1.conf -i wlan0 -D hostap -N \
- -c wpa2.conf -i ath0 -D madwifi
+ -c wpa1.conf -i wlan0 -D nl80211 -N \
+ -c wpa2.conf -i ath0 -D wext
</programlisting></blockquote>
</refsect1>
@@ -537,86 +508,6 @@
<title>Supported Drivers</title>
<variablelist>
<varlistentry>
- <term>Host AP driver for Prism2/2.5/3 (development
- snapshot/v0.2.x)</term>
- <listitem>
- <para> (http://hostap.epitest.fi/) Driver needs to be set in
- Managed mode (<emphasis>iwconfig wlan0 mode managed</emphasis>).
- Please note that station firmware version needs to be 1.7.0 or
- newer to work in WPA mode.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Linuxant DriverLoader</term>
- <listitem>
- <para>(http://www.linuxant.com/driverloader/)
- with Windows NDIS driver for your wlan card supporting WPA.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Agere Systems Inc. Linux Driver</term>
- <listitem>
- <para> (http://www.agere.com/support/drivers/) Please note
- that the driver interface file (driver_hermes.c) and hardware
- specific include files are not included in the wpa_supplicant
- distribution. You will need to copy these from the source
- package of the Agere driver.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>madwifi driver for cards based on Atheros chip set (ar521x)</term>
- <listitem>
- <para> (http://sourceforge.net/projects/madwifi/) Please
- note that you will need to modify the wpa_supplicant .config
- file to use the correct path for the madwifi driver root
- directory (CFLAGS += -I../madwifi/wpa line in example
- defconfig).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Linux ndiswrapper</term>
- <listitem>
- <para> (http://ndiswrapper.sourceforge.net/) with Windows
- NDIS driver.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Broadcom wl.o driver</term>
- <listitem>
- <para> This is a generic Linux driver for Broadcom IEEE
- 802.11a/g cards. However, it is proprietary driver that is
- not publicly available except for couple of exceptions, mainly
- Broadcom-based APs/wireless routers that use Linux. The driver
- binary can be downloaded, e.g., from Linksys support site
- (http://www.linksys.com/support/gpl.asp) for Linksys
- WRT54G. The GPL tarball includes cross-compiler and the needed
- header file, wlioctl.h, for compiling wpa_supplicant. This
- driver support in wpa_supplicant is expected to work also with
- other devices based on Broadcom driver (assuming the driver
- includes client mode support).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term> Intel ipw2100 driver</term>
- <listitem>
- <para> (http://sourceforge.net/projects/ipw2100/)</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Intel ipw2200 driver</term>
- <listitem>
- <para> (http://sourceforge.net/projects/ipw2200/)</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term>Linux wireless extensions</term>
<listitem>
<para>In theory, any driver that supports Linux wireless
@@ -788,12 +679,12 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2007,
+ <para>wpa_supplicant is copyright (c) 2003-2012,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
- <para>This program is dual-licensed under both the GPL version 2
- and BSD license. Either license may be used at your option.</para>
+ <para>This program is licensed under the BSD license (the one with
+ advertisement clause removed).</para>
</refsect1>
</refentry>
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index b9ea291..f968251 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -427,6 +427,13 @@
return 0;
}
+static inline int wpa_drv_deinit_p2p_cli(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->driver->deinit_p2p_cli)
+ return wpa_s->driver->deinit_p2p_cli(wpa_s->drv_priv);
+ return 0;
+}
+
static inline void wpa_drv_suspend(struct wpa_supplicant *wpa_s)
{
if (wpa_s->driver->suspend)
@@ -667,13 +674,20 @@
wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
}
-#ifdef ANDROID_P2P
+static inline int wpa_drv_radio_disable(struct wpa_supplicant *wpa_s,
+ int disabled)
+{
+ if (!wpa_s->driver->radio_disable)
+ return -1;
+ return wpa_s->driver->radio_disable(wpa_s->drv_priv, disabled);
+}
+
static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s,
- int freq)
+ unsigned int freq)
{
if (!wpa_s->driver->switch_channel)
return -1;
return wpa_s->driver->switch_channel(wpa_s->drv_priv, freq);
}
-#endif
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 65e6742..e53e156 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - test code
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -278,7 +278,9 @@
}
}
- radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr);
+ if (radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr)
+ < 0)
+ goto fail;
return;
fail:
@@ -856,7 +858,7 @@
unsigned char aka_ik[IK_LEN];
unsigned char aka_ck[CK_LEN];
- scard = scard_init(SCARD_TRY_BOTH);
+ scard = scard_init(SCARD_TRY_BOTH, NULL);
if (scard == NULL)
return -1;
if (scard_set_pin(scard, "1234")) {
@@ -956,7 +958,7 @@
wpa_debug_level = 99;
}
- scard = scard_init(SCARD_GSM_SIM_ONLY);
+ scard = scard_init(SCARD_GSM_SIM_ONLY, NULL);
if (scard == NULL) {
printf("Failed to open smartcard connection\n");
return -1;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 5ce5b72..c4b3862 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -35,6 +35,7 @@
#include "gas_query.h"
#include "p2p_supplicant.h"
#include "bgscan.h"
+#include "autoscan.h"
#include "ap.h"
#include "bss.h"
#include "scan.h"
@@ -57,7 +58,7 @@
return -1;
}
- if (ssid->disabled) {
+ if (wpas_network_disabled(wpa_s, ssid)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is disabled");
return -1;
}
@@ -103,6 +104,8 @@
{
int bssid_changed;
+ wnm_bss_keep_alive_deinit(wpa_s);
+
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
wpa_s->ibss_rsn = NULL;
@@ -122,6 +125,9 @@
bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
os_memset(wpa_s->bssid, 0, ETH_ALEN);
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
#ifdef CONFIG_P2P
os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
#endif /* CONFIG_P2P */
@@ -241,7 +247,8 @@
if (eap->vendor == EAP_VENDOR_IETF) {
if (eap->method == EAP_TYPE_SIM)
sim = 1;
- else if (eap->method == EAP_TYPE_AKA)
+ else if (eap->method == EAP_TYPE_AKA ||
+ eap->method == EAP_TYPE_AKA_PRIME)
aka = 1;
}
eap++;
@@ -250,7 +257,9 @@
if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_SIM) == NULL)
sim = 0;
- if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL)
+ if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL &&
+ eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME) ==
+ NULL)
aka = 0;
if (!sim && !aka) {
@@ -269,7 +278,7 @@
else
type = SCARD_GSM_SIM_ONLY;
- wpa_s->scard = scard_init(type);
+ wpa_s->scard = scard_init(type, NULL);
if (wpa_s->scard == NULL) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
"(pcsc-lite)");
@@ -612,7 +621,7 @@
e = wpa_blacklist_get(wpa_s, bss->bssid);
if (e) {
int limit = 1;
- if (wpa_supplicant_enabled_networks(wpa_s->conf) == 1) {
+ if (wpa_supplicant_enabled_networks(wpa_s) == 1) {
/*
* When only a single network is enabled, we can
* trigger blacklisting on the first failure. This
@@ -640,7 +649,7 @@
for (ssid = group; ssid; ssid = ssid->pnext) {
int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
- if (ssid->disabled) {
+ if (wpas_network_disabled(wpa_s, ssid)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
continue;
}
@@ -805,7 +814,7 @@
static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
int timeout_sec, int timeout_usec)
{
- if (!wpa_supplicant_enabled_networks(wpa_s->conf)) {
+ if (!wpa_supplicant_enabled_networks(wpa_s)) {
/*
* No networks are enabled; short-circuit request so
* we don't wait timeout seconds before transitioning
@@ -876,7 +885,7 @@
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
for (ssid = wpa_s->conf->pssid[prio]; ssid; ssid = ssid->pnext)
{
- if (ssid->disabled)
+ if (wpas_network_disabled(wpa_s, ssid))
continue;
if (ssid->mode == IEEE80211_MODE_IBSS ||
ssid->mode == IEEE80211_MODE_AP)
@@ -989,13 +998,14 @@
}
return 1;
-#else
+#else /* CONFIG_NO_ROAMING */
return 0;
-#endif
+#endif /* CONFIG_NO_ROAMING */
}
-/* Return < 0 if no scan results could be fetched. */
+/* Return < 0 if no scan results could be fetched or if scan results should not
+ * be shared with other virtual interfaces. */
#ifdef ANDROID_P2P
static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
union wpa_event_data *data, int suppress_event)
@@ -1070,7 +1080,7 @@
scan_res_handler(wpa_s, scan_res);
wpa_scan_results_free(scan_res);
- return 0;
+ return -2;
}
if (ap) {
@@ -1084,20 +1094,34 @@
}
#ifdef ANDROID_P2P
if(!suppress_event)
-#endif
{
wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
wpas_notify_scan_results(wpa_s);
}
+#else
+ wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+ wpas_notify_scan_results(wpa_s);
+#endif
wpas_notify_scan_done(wpa_s, 1);
+ if (sme_proc_obss_scan(wpa_s) > 0) {
+ 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 (autoscan_notify_scan(wpa_s, scan_res)) {
+ wpa_scan_results_free(scan_res);
+ return 0;
+ }
+
if (wpa_s->disconnected) {
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
wpa_scan_results_free(scan_res);
@@ -1139,6 +1163,9 @@
int timeout_sec = wpa_s->scan_interval;
int timeout_usec = 0;
#ifdef CONFIG_P2P
+ if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
+ return 0;
+
if (wpa_s->p2p_in_provisioning) {
/*
* Use shorter wait during P2P Provisioning
@@ -1228,6 +1255,82 @@
#endif /* CONFIG_NO_SCAN_PROCESSING */
+#ifdef CONFIG_WNM
+
+static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (wpa_s->wpa_state < WPA_ASSOCIATED)
+ return;
+
+ wpa_printf(MSG_DEBUG, "WNM: Send keep-alive to AP " MACSTR,
+ MAC2STR(wpa_s->bssid));
+ /* TODO: could skip this if normal data traffic has been sent */
+ /* TODO: Consider using some more appropriate data frame for this */
+ if (wpa_s->l2)
+ l2_packet_send(wpa_s->l2, wpa_s->bssid, 0x0800, (u8 *) "", 0);
+
+#ifdef CONFIG_SME
+ if (wpa_s->sme.bss_max_idle_period) {
+ unsigned int msec;
+ msec = wpa_s->sme.bss_max_idle_period * 1024; /* times 1000 */
+ if (msec > 100)
+ msec -= 100;
+ eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+ wnm_bss_keep_alive, wpa_s, NULL);
+ }
+#endif /* CONFIG_SME */
+}
+
+
+static void wnm_process_assoc_resp(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+
+ if (ies == NULL)
+ return;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+ return;
+
+#ifdef CONFIG_SME
+ if (elems.bss_max_idle_period) {
+ unsigned int msec;
+ wpa_s->sme.bss_max_idle_period =
+ WPA_GET_LE16(elems.bss_max_idle_period);
+ wpa_printf(MSG_DEBUG, "WNM: BSS Max Idle Period: %u (* 1000 "
+ "TU)%s", wpa_s->sme.bss_max_idle_period,
+ (elems.bss_max_idle_period[2] & 0x01) ?
+ " (protected keep-live required)" : "");
+ if (wpa_s->sme.bss_max_idle_period == 0)
+ wpa_s->sme.bss_max_idle_period = 1;
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+ eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+ /* msec times 1000 */
+ msec = wpa_s->sme.bss_max_idle_period * 1024;
+ if (msec > 100)
+ msec -= 100;
+ eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+ wnm_bss_keep_alive, wpa_s,
+ NULL);
+ }
+ }
+#endif /* CONFIG_SME */
+}
+
+#endif /* CONFIG_WNM */
+
+
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WNM
+ eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+#endif /* CONFIG_WNM */
+}
+
+
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
@@ -1245,6 +1348,10 @@
wpa_tdls_assoc_resp_ies(wpa_s->wpa, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_WNM
+ wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+#endif /* CONFIG_WNM */
}
if (data->assoc_info.beacon_ies)
wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -1702,9 +1809,18 @@
if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
wpas_connection_failed(wpa_s, bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
- " reason=%d",
- MAC2STR(bssid), reason_code);
+ if (locally_generated)
+ wpa_s->disconnect_reason = -reason_code;
+ else
+ wpa_s->disconnect_reason = reason_code;
+ wpas_notify_disconnect_reason(wpa_s);
+ if (!is_zero_ether_addr(bssid) ||
+ wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
+ " reason=%d%s",
+ MAC2STR(bssid), reason_code,
+ locally_generated ? " locally_generated=1" : "");
+ }
if (wpa_supplicant_dynamic_keys(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
wpa_s->keys_cleared = 0;
@@ -1867,11 +1983,13 @@
wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
"driver after interface was added");
}
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
break;
case EVENT_INTERFACE_REMOVED:
wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
wpa_s->interface_removed = 1;
wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
l2_packet_deinit(wpa_s->l2);
wpa_s->l2 = NULL;
#ifdef CONFIG_IBSS_RSN
@@ -2104,8 +2222,7 @@
{
int level = MSG_DEBUG;
- if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
- data->rx_mgmt.frame_len >= 24) {
+ if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) {
const struct ieee80211_hdr *hdr;
u16 fc;
hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
@@ -2161,7 +2278,8 @@
wpas_p2p_disassoc_notif(
wpa_s, data->disassoc_info.addr, reason_code,
data->disassoc_info.ie,
- data->disassoc_info.ie_len);
+ data->disassoc_info.ie_len,
+ locally_generated);
#endif /* CONFIG_P2P */
}
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
@@ -2189,13 +2307,6 @@
"Deauthentication frame IE(s)",
data->deauth_info.ie,
data->deauth_info.ie_len);
-#ifdef CONFIG_P2P
- wpas_p2p_deauth_notif(
- wpa_s, data->deauth_info.addr,
- reason_code,
- data->deauth_info.ie,
- data->deauth_info.ie_len);
-#endif /* CONFIG_P2P */
}
}
#ifdef CONFIG_AP
@@ -2212,6 +2323,15 @@
#endif /* CONFIG_AP */
wpa_supplicant_event_disassoc(wpa_s, reason_code,
locally_generated);
+#ifdef CONFIG_P2P
+ if (event == EVENT_DEAUTH && data) {
+ wpas_p2p_deauth_notif(wpa_s, data->deauth_info.addr,
+ reason_code,
+ data->deauth_info.ie,
+ data->deauth_info.ie_len,
+ locally_generated);
+ }
+#endif /* CONFIG_P2P */
break;
case EVENT_MICHAEL_MIC_FAILURE:
wpa_supplicant_event_michael_mic_failure(wpa_s, data);
@@ -2263,8 +2383,7 @@
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
sme_event_assoc_reject(wpa_s, data);
#ifdef ANDROID_P2P
-#ifdef CONFIG_P2P
- else if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+ else {
if(!wpa_s->current_ssid) {
wpa_printf(MSG_ERROR, "current_ssid == NULL");
@@ -2291,12 +2410,13 @@
*/
wpa_printf(MSG_ERROR, "Assoc retry threshold reached. "
"Disabling the network");
- wpa_s->current_ssid->assoc_retry = 0;
wpa_supplicant_disable_network(wpa_s, wpa_s->current_ssid);
- wpas_p2p_group_remove(wpa_s, wpa_s->ifname);
+#ifdef CONFIG_P2P
+ if(wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
+ wpas_p2p_group_remove(wpa_s, wpa_s->ifname);
+#endif
}
}
-#endif
#endif /* ANDROID_P2P */
break;
case EVENT_AUTH_TIMED_OUT:
@@ -2382,15 +2502,32 @@
ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
data->rx_from_unknown.wds);
break;
- case EVENT_RX_MGMT:
+ case EVENT_CH_SWITCH:
+ if (!data)
+ break;
+ if (!wpa_s->ap_iface) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "AP: Ignore channel switch "
+ "event in non-AP mode");
+ break;
+ }
+
+#ifdef CONFIG_AP
+ wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
+ data->ch_switch.ht_enabled,
+ data->ch_switch.ch_offset);
+#endif /* CONFIG_AP */
+ break;
+ case EVENT_RX_MGMT: {
+ u16 fc, stype;
+ const struct ieee80211_mgmt *mgmt;
+
+ mgmt = (const struct ieee80211_mgmt *)
+ data->rx_mgmt.frame;
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+
if (wpa_s->ap_iface == NULL) {
#ifdef CONFIG_P2P
- u16 fc, stype;
- const struct ieee80211_mgmt *mgmt;
- mgmt = (const struct ieee80211_mgmt *)
- data->rx_mgmt.frame;
- fc = le_to_host16(mgmt->frame_control);
- stype = WLAN_FC_GET_STYPE(fc);
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
data->rx_mgmt.frame_len > 24) {
const u8 *src = mgmt->sa;
@@ -2398,8 +2535,10 @@
size_t ie_len = data->rx_mgmt.frame_len -
(mgmt->u.probe_req.variable -
data->rx_mgmt.frame);
- wpas_p2p_probe_req_rx(wpa_s, src, mgmt->da,
- mgmt->bssid, ie, ie_len);
+ wpas_p2p_probe_req_rx(
+ wpa_s, src, mgmt->da,
+ mgmt->bssid, ie, ie_len,
+ data->rx_mgmt.ssi_signal);
break;
}
#endif /* CONFIG_P2P */
@@ -2407,8 +2546,22 @@
"management frame in non-AP mode");
break;
}
+
+ if (stype == WLAN_FC_STYPE_PROBE_REQ &&
+ data->rx_mgmt.frame_len > 24) {
+ const u8 *ie = mgmt->u.probe_req.variable;
+ size_t ie_len = data->rx_mgmt.frame_len -
+ (mgmt->u.probe_req.variable -
+ data->rx_mgmt.frame);
+
+ wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da,
+ mgmt->bssid, ie, ie_len,
+ data->rx_mgmt.ssi_signal);
+ }
+
ap_mgmt_rx(wpa_s, &data->rx_mgmt);
break;
+ }
#endif /* CONFIG_AP */
case EVENT_RX_ACTION:
wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
@@ -2475,7 +2628,8 @@
data->rx_probe_req.da,
data->rx_probe_req.bssid,
data->rx_probe_req.ie,
- data->rx_probe_req.ie_len);
+ data->rx_probe_req.ie_len,
+ data->rx_probe_req.ssi_signal);
break;
}
#endif /* CONFIG_AP */
@@ -2484,7 +2638,8 @@
data->rx_probe_req.da,
data->rx_probe_req.bssid,
data->rx_probe_req.ie,
- data->rx_probe_req.ie_len);
+ data->rx_probe_req.ie_len,
+ data->rx_probe_req.ssi_signal);
#endif /* CONFIG_P2P */
break;
case EVENT_REMAIN_ON_CHANNEL:
@@ -2612,6 +2767,11 @@
case EVENT_CHANNEL_LIST_CHANGED:
if (wpa_s->drv_priv == NULL)
break; /* Ignore event during drv initialization */
+
+ free_hw_features(wpa_s);
+ wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
+ wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
+
#ifdef CONFIG_P2P
wpas_p2p_update_channel_list(wpa_s);
#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/examples/dbus-listen-preq.py b/wpa_supplicant/examples/dbus-listen-preq.py
new file mode 100755
index 0000000..5ac9859
--- /dev/null
+++ b/wpa_supplicant/examples/dbus-listen-preq.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+
+import dbus
+import sys
+import time
+import gobject
+from dbus.mainloop.glib import DBusGMainLoop
+
+WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1"
+WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1"
+WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1"
+WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface"
+
+def usage():
+ print "Usage: %s <ifname>" % sys.argv[0]
+ print "Press Ctrl-C to stop"
+
+def ProbeRequest(args):
+ if 'addr' in args:
+ print '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']),
+ if 'dst' in args:
+ print '-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']),
+ if 'bssid' in args:
+ print '(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']),
+ if 'signal' in args:
+ print 'signal:%d' % args['signal'],
+ if 'ies' in args:
+ print 'have IEs (%d bytes)' % len(args['ies']),
+ print ''
+
+if __name__ == "__main__":
+ global bus
+ global wpas_obj
+ global if_obj
+ global p2p_iface
+
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+ wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
+
+ # Print list of i/f if no one is specified
+ if (len(sys.argv) < 2) :
+ usage()
+ sys.exit(0)
+
+ wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
+
+ ifname = sys.argv[1]
+
+ path = wpas.GetInterface(ifname)
+
+ if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+ iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE)
+
+ bus.add_signal_receiver(ProbeRequest,
+ dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+ signal_name="ProbeRequest")
+
+ iface.SubscribeProbeReq()
+
+ gobject.MainLoop().run()
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
new file mode 100644
index 0000000..2afa16c
--- /dev/null
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2009, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_common.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 "config.h"
+#include "bss.h"
+#include "gas_query.h"
+#include "interworking.h"
+#include "hs20_supplicant.h"
+
+
+void wpas_hs20_add_indication(struct wpabuf *buf)
+{
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 5);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE);
+ wpabuf_put_u8(buf, 0x00); /* Hotspot Configuration */
+}
+
+
+struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+ size_t payload_len)
+{
+ struct wpabuf *buf;
+ u8 *len_pos;
+
+ buf = gas_anqp_build_initial_req(0, 100 + payload_len);
+ if (buf == NULL)
+ return NULL;
+
+ len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ if (stypes == BIT(HS20_STYPE_NAI_HOME_REALM_QUERY)) {
+ wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ if (payload)
+ wpabuf_put_data(buf, payload, payload_len);
+ } else {
+ u8 i;
+ wpabuf_put_u8(buf, HS20_STYPE_QUERY_LIST);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ for (i = 0; i < 32; i++) {
+ if (stypes & BIT(i))
+ wpabuf_put_u8(buf, i);
+ }
+ }
+ gas_anqp_set_element_len(buf, len_pos);
+
+ gas_anqp_set_len(buf);
+
+ return buf;
+}
+
+
+int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
+ const u8 *payload, size_t payload_len)
+{
+ struct wpabuf *buf;
+ int ret = 0;
+ int freq;
+ struct wpa_bss *bss;
+ int res;
+
+ freq = wpa_s->assoc_freq;
+ bss = wpa_bss_get_bssid(wpa_s, dst);
+ if (bss)
+ freq = bss->freq;
+ if (freq <= 0)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "HS20: ANQP Query Request to " MACSTR " for "
+ "subtypes 0x%x", MAC2STR(dst), stypes);
+
+ buf = hs20_build_anqp_req(stypes, payload, payload_len);
+ if (buf == NULL)
+ return -1;
+
+ res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ ret = -1;
+ } else
+ wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
+ "%u", res);
+
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data, size_t slen)
+{
+ const u8 *pos = data;
+ u8 subtype;
+ struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+
+ if (slen < 2)
+ return;
+
+ subtype = *pos++;
+ slen--;
+
+ pos++; /* Reserved */
+ slen--;
+
+ switch (subtype) {
+ case HS20_STYPE_CAPABILITY_LIST:
+ wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ " HS Capability List", MAC2STR(sa));
+ wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen);
+ break;
+ case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
+ wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ " Operator Friendly Name", MAC2STR(sa));
+ wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
+ if (bss) {
+ wpabuf_free(bss->hs20_operator_friendly_name);
+ bss->hs20_operator_friendly_name =
+ wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+ case HS20_STYPE_WAN_METRICS:
+ wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ " WAN Metrics", MAC2STR(sa));
+ wpa_hexdump_ascii(MSG_DEBUG, "WAN Metrics", pos, slen);
+ if (bss) {
+ wpabuf_free(bss->hs20_wan_metrics);
+ bss->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+ case HS20_STYPE_CONNECTION_CAPABILITY:
+ wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ " Connection Capability", MAC2STR(sa));
+ wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
+ if (bss) {
+ wpabuf_free(bss->hs20_connection_capability);
+ bss->hs20_connection_capability =
+ wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+ case HS20_STYPE_OPERATING_CLASS:
+ wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ " Operating Class", MAC2STR(sa));
+ wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
+ if (bss) {
+ wpabuf_free(bss->hs20_operating_class);
+ bss->hs20_operating_class =
+ wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
+ break;
+ }
+}
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
new file mode 100644
index 0000000..6eb3926
--- /dev/null
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HS20_SUPPLICANT_H
+#define HS20_SUPPLICANT_H
+
+void wpas_hs20_add_indication(struct wpabuf *buf);
+
+int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
+ const u8 *payload, size_t payload_len);
+struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+ size_t payload_len);
+void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data, size_t slen);
+
+#endif /* HS20_SUPPLICANT_H */
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index ac89ff8..515d94b 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1,6 +1,6 @@
/*
* Interworking (IEEE 802.11u)
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,15 +12,18 @@
#include "common/ieee802_11_defs.h"
#include "common/gas.h"
#include "common/wpa_ctrl.h"
+#include "utils/pcsc_funcs.h"
#include "drivers/driver.h"
#include "eap_common/eap_defs.h"
#include "eap_peer/eap_methods.h"
#include "wpa_supplicant_i.h"
#include "config.h"
+#include "config_ssid.h"
#include "bss.h"
#include "scan.h"
#include "notify.h"
#include "gas_query.h"
+#include "hs20_supplicant.h"
#include "interworking.h"
@@ -39,6 +42,19 @@
static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
+static void interworking_reconnect(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ }
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
struct wpabuf *extra)
{
@@ -100,6 +116,28 @@
wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
MAC2STR(bss->bssid));
+#ifdef CONFIG_HS20
+ if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+ u8 *len_pos;
+
+ extra = wpabuf_alloc(100);
+ if (!extra)
+ return -1;
+
+ len_pos = gas_anqp_add_element(extra, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(extra, OUI_WFA);
+ wpabuf_put_u8(extra, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST);
+ wpabuf_put_u8(extra, 0); /* Reserved */
+ wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST);
+ wpabuf_put_u8(extra, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+ wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
+ wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
+ wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
+ gas_anqp_set_element_len(extra, len_pos);
+ }
+#endif /* CONFIG_HS20 */
+
buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
extra);
wpabuf_free(extra);
@@ -416,20 +454,41 @@
}
-static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
+static int nai_realm_cred_cert(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_TLS) {
+ /* Only EAP-TLS supported for credential authentication */
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
struct nai_realm *realm)
{
u8 e;
- if (wpa_s->conf->home_username == NULL ||
- wpa_s->conf->home_username[0] == '\0' ||
- wpa_s->conf->home_password == NULL ||
- wpa_s->conf->home_password[0] == '\0')
+ if (cred == NULL ||
+ cred->username == NULL ||
+ cred->username[0] == '\0' ||
+ ((cred->password == NULL ||
+ cred->password[0] == '\0') &&
+ (cred->private_key == NULL ||
+ cred->private_key[0] == '\0')))
return NULL;
for (e = 0; e < realm->eap_count; e++) {
struct nai_realm_eap *eap = &realm->eap[e];
- if (nai_realm_cred_username(eap))
+ if (cred->password && cred->password[0] &&
+ nai_realm_cred_username(eap))
+ return eap;
+ if (cred->private_key && cred->private_key[0] &&
+ nai_realm_cred_cert(eap))
return eap;
}
@@ -439,21 +498,17 @@
#ifdef INTERWORKING_3GPP
-static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
+static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
{
- const char *sep;
u8 plmn[3];
const u8 *pos, *end;
u8 udhl;
- sep = os_strchr(imsi, '-');
- if (sep == NULL || (sep - imsi != 5 && sep - imsi != 6))
- return 0;
-
/* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
plmn[1] = imsi[2] - '0';
- if (sep - imsi == 6)
+ /* default to MNC length 3 if unknown */
+ if (mnc_len != 2)
plmn[1] |= (imsi[5] - '0') << 4;
else
plmn[1] |= 0xf0;
@@ -505,10 +560,11 @@
}
-static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
+static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
+ char prefix)
{
const char *sep, *msin;
- char nai[100], *end, *pos;
+ char *end, *pos;
size_t msin_len, plmn_len;
/*
@@ -532,8 +588,9 @@
msin_len = os_strlen(msin);
pos = nai;
- end = pos + sizeof(nai);
- *pos++ = prefix;
+ end = nai + nai_len;
+ if (prefix)
+ *pos++ = prefix;
os_memcpy(pos, imsi, plmn_len);
pos += plmn_len;
os_memcpy(pos, msin, msin_len);
@@ -551,6 +608,15 @@
pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
imsi[0], imsi[1], imsi[2]);
+ return 0;
+}
+
+
+static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
+{
+ char nai[100];
+ if (build_root_nai(nai, sizeof(nai), imsi, prefix) < 0)
+ return -1;
return wpa_config_set_quoted(ssid, "identity", nai);
}
@@ -561,9 +627,47 @@
struct wpa_bss *bss)
{
#ifdef INTERWORKING_3GPP
+ struct wpa_cred *cred;
struct wpa_ssid *ssid;
const u8 *ie;
+ if (bss->anqp_3gpp == NULL)
+ return -1;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ char *sep;
+ const char *imsi;
+ int mnc_len;
+
+#ifdef PCSC_FUNCS
+ if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
+ wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ goto compare;
+ }
+#endif /* PCSC_FUNCS */
+
+ if (cred->imsi == NULL || !cred->imsi[0] ||
+ cred->milenage == NULL || !cred->milenage[0])
+ continue;
+
+ sep = os_strchr(cred->imsi, '-');
+ if (sep == NULL ||
+ (sep - cred->imsi != 5 && sep - cred->imsi != 6))
+ continue;
+ mnc_len = sep - cred->imsi - 3;
+ imsi = cred->imsi;
+
+#ifdef PCSC_FUNCS
+ compare:
+#endif /* PCSC_FUNCS */
+ if (plmn_id_match(bss->anqp_3gpp, imsi, mnc_len))
+ break;
+ }
+ if (cred == NULL)
+ return -1;
+
ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
if (ie == NULL)
return -1;
@@ -576,6 +680,7 @@
wpas_notify_network_added(wpa_s, ssid);
wpa_config_set_network_defaults(ssid);
+ ssid->priority = cred->priority;
ssid->temporary = 1;
ssid->ssid = os_zalloc(ie[1] + 1);
if (ssid->ssid == NULL)
@@ -588,27 +693,32 @@
wpa_printf(MSG_DEBUG, "EAP-SIM not supported");
goto fail;
}
- if (set_root_nai(ssid, wpa_s->conf->home_imsi, '1') < 0) {
+ if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
+ wpa_config_set(ssid, "eap", "AKA", 0);
+ if (!cred->pcsc && set_root_nai(ssid, cred->imsi, '1') < 0) {
wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
goto fail;
}
- if (wpa_s->conf->home_milenage && wpa_s->conf->home_milenage[0]) {
+ if (cred->milenage && cred->milenage[0]) {
if (wpa_config_set_quoted(ssid, "password",
- wpa_s->conf->home_milenage) < 0)
+ cred->milenage) < 0)
goto fail;
- } else {
- /* TODO: PIN */
+ } else if (cred->pcsc) {
if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
goto fail;
+ if (wpa_s->conf->pcsc_pin &&
+ wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin)
+ < 0)
+ goto fail;
}
- if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
- wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
- < 0)
+ if (cred->password && cred->password[0] &&
+ wpa_config_set_quoted(ssid, "password", cred->password) < 0)
goto fail;
- wpa_supplicant_select_network(wpa_s, ssid);
+ wpa_config_update_prio_list(wpa_s->conf);
+ interworking_reconnect(wpa_s);
return 0;
@@ -622,6 +732,7 @@
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
+ struct wpa_cred *cred;
struct wpa_ssid *ssid;
struct nai_realm *realm;
struct nai_realm_eap *eap = NULL;
@@ -629,7 +740,7 @@
char buf[100];
const u8 *ie;
- if (bss == NULL)
+ if (wpa_s->conf->cred == NULL || bss == NULL)
return -1;
ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
if (ie == NULL || ie[1] == 0) {
@@ -645,10 +756,14 @@
count = 0;
}
- for (i = 0; i < count; i++) {
- if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
- continue;
- eap = nai_realm_find_eap(wpa_s, &realm[i]);
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ for (i = 0; i < count; i++) {
+ if (!nai_realm_match(&realm[i], cred->realm))
+ continue;
+ eap = nai_realm_find_eap(cred, &realm[i]);
+ if (eap)
+ break;
+ }
if (eap)
break;
}
@@ -677,6 +792,7 @@
}
wpas_notify_network_added(wpa_s, ssid);
wpa_config_set_network_defaults(ssid);
+ ssid->priority = cred->priority;
ssid->temporary = 1;
ssid->ssid = os_zalloc(ie[1] + 1);
if (ssid->ssid == NULL)
@@ -688,14 +804,56 @@
eap->method), 0) < 0)
goto fail;
- if (wpa_s->conf->home_username && wpa_s->conf->home_username[0] &&
- wpa_config_set_quoted(ssid, "identity",
- wpa_s->conf->home_username) < 0)
+ if (eap->method == EAP_TYPE_TTLS &&
+ cred->username && cred->username[0]) {
+ const char *pos;
+ char *anon;
+ /* Use anonymous NAI in Phase 1 */
+ pos = os_strchr(cred->username, '@');
+ if (pos) {
+ size_t buflen = 9 + os_strlen(pos) + 1;
+ anon = os_malloc(buflen);
+ if (anon == NULL)
+ goto fail;
+ os_snprintf(anon, buflen, "anonymous%s", pos);
+ } else if (cred->realm) {
+ size_t buflen = 10 + os_strlen(cred->realm) + 1;
+ anon = os_malloc(buflen);
+ if (anon == NULL)
+ goto fail;
+ os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
+ } else {
+ anon = os_strdup("anonymous");
+ if (anon == NULL)
+ goto fail;
+ }
+ if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
+ 0) {
+ os_free(anon);
+ goto fail;
+ }
+ os_free(anon);
+ }
+
+ if (cred->username && cred->username[0] &&
+ wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
goto fail;
- if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
- wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
- < 0)
+ if (cred->password && cred->password[0] &&
+ wpa_config_set_quoted(ssid, "password", cred->password) < 0)
+ goto fail;
+
+ if (cred->client_cert && cred->client_cert[0] &&
+ wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
+ goto fail;
+
+ if (cred->private_key && cred->private_key[0] &&
+ wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
+ goto fail;
+
+ if (cred->private_key_passwd && cred->private_key_passwd[0] &&
+ wpa_config_set_quoted(ssid, "private_key_passwd",
+ cred->private_key_passwd) < 0)
goto fail;
switch (eap->method) {
@@ -737,16 +895,18 @@
if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
goto fail;
break;
+ case EAP_TYPE_TLS:
+ break;
}
- if (wpa_s->conf->home_ca_cert && wpa_s->conf->home_ca_cert[0] &&
- wpa_config_set_quoted(ssid, "ca_cert", wpa_s->conf->home_ca_cert) <
- 0)
+ if (cred->ca_cert && cred->ca_cert[0] &&
+ wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
goto fail;
nai_realm_free(realm, count);
- wpa_supplicant_select_network(wpa_s, ssid);
+ wpa_config_update_prio_list(wpa_s->conf);
+ interworking_reconnect(wpa_s);
return 0;
@@ -758,41 +918,71 @@
}
-static int interworking_credentials_available_3gpp(
+static struct wpa_cred * interworking_credentials_available_3gpp(
struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
- int ret = 0;
+ struct wpa_cred *cred, *selected = NULL;
+ int ret;
#ifdef INTERWORKING_3GPP
if (bss->anqp_3gpp == NULL)
- return ret;
+ return NULL;
- if (wpa_s->conf->home_imsi == NULL || !wpa_s->conf->home_imsi[0] ||
- wpa_s->conf->home_milenage == NULL ||
- !wpa_s->conf->home_milenage[0])
- return ret;
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ char *sep;
+ const char *imsi;
+ int mnc_len;
- wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from " MACSTR,
- MAC2STR(bss->bssid));
- ret = plmn_id_match(bss->anqp_3gpp, wpa_s->conf->home_imsi);
- wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+#ifdef PCSC_FUNCS
+ if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
+ wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ goto compare;
+ }
+#endif /* PCSC_FUNCS */
+
+ if (cred->imsi == NULL || !cred->imsi[0] ||
+ cred->milenage == NULL || !cred->milenage[0])
+ continue;
+
+ sep = os_strchr(cred->imsi, '-');
+ if (sep == NULL ||
+ (sep - cred->imsi != 5 && sep - cred->imsi != 6))
+ continue;
+ mnc_len = sep - cred->imsi - 3;
+ imsi = cred->imsi;
+
+#ifdef PCSC_FUNCS
+ compare:
+#endif /* PCSC_FUNCS */
+ wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
+ MACSTR, MAC2STR(bss->bssid));
+ ret = plmn_id_match(bss->anqp_3gpp, imsi, mnc_len);
+ wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+ if (ret) {
+ if (selected == NULL ||
+ selected->priority < cred->priority)
+ selected = cred;
+ }
+ }
#endif /* INTERWORKING_3GPP */
- return ret;
+ return selected;
}
-static int interworking_credentials_available_realm(
+static struct wpa_cred * interworking_credentials_available_realm(
struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
+ struct wpa_cred *cred, *selected = NULL;
struct nai_realm *realm;
u16 count, i;
- int found = 0;
if (bss->anqp_nai_realm == NULL)
- return 0;
+ return NULL;
- if (wpa_s->conf->home_realm == NULL)
- return 0;
+ if (wpa_s->conf->cred == NULL)
+ return NULL;
wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
MACSTR, MAC2STR(bss->bssid));
@@ -800,50 +990,198 @@
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
- return 0;
+ return NULL;
}
- for (i = 0; i < count; i++) {
- if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->realm == NULL)
continue;
- if (nai_realm_find_eap(wpa_s, &realm[i])) {
- found++;
- break;
+
+ for (i = 0; i < count; i++) {
+ if (!nai_realm_match(&realm[i], cred->realm))
+ continue;
+ if (nai_realm_find_eap(cred, &realm[i])) {
+ if (selected == NULL ||
+ selected->priority < cred->priority)
+ selected = cred;
+ break;
+ }
}
}
nai_realm_free(realm, count);
- return found;
+ return selected;
}
-static int interworking_credentials_available(struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss)
+static struct wpa_cred * interworking_credentials_available(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
- return interworking_credentials_available_realm(wpa_s, bss) ||
- interworking_credentials_available_3gpp(wpa_s, bss);
+ struct wpa_cred *cred, *cred2;
+
+ cred = interworking_credentials_available_realm(wpa_s, bss);
+ cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
+ if (cred && cred2 && cred2->priority >= cred->priority)
+ cred = cred2;
+ if (!cred)
+ cred = cred2;
+
+ return cred;
+}
+
+
+static int domain_name_list_contains(struct wpabuf *domain_names,
+ const char *domain)
+{
+ const u8 *pos, *end;
+ size_t len;
+
+ len = os_strlen(domain);
+ pos = wpabuf_head(domain_names);
+ end = pos + wpabuf_len(domain_names);
+
+ while (pos + 1 < end) {
+ if (pos + 1 + pos[0] > end)
+ break;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name",
+ pos + 1, pos[0]);
+ if (pos[0] == len &&
+ os_strncasecmp(domain, (const char *) (pos + 1), len) == 0)
+ return 1;
+
+ pos += 1 + pos[0];
+ }
+
+ return 0;
+}
+
+
+static int interworking_home_sp(struct wpa_supplicant *wpa_s,
+ struct wpabuf *domain_names)
+{
+ struct wpa_cred *cred;
+#ifdef INTERWORKING_3GPP
+ char nai[100], *realm;
+#endif /* INTERWORKING_3GPP */
+
+ if (domain_names == NULL || wpa_s->conf->cred == NULL)
+ return -1;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+#ifdef INTERWORKING_3GPP
+ if (cred->imsi &&
+ build_root_nai(nai, sizeof(nai), cred->imsi, 0) == 0) {
+ realm = os_strchr(nai, '@');
+ if (realm)
+ realm++;
+ wpa_printf(MSG_DEBUG, "Interworking: Search for match "
+ "with SIM/USIM domain %s", realm);
+ if (realm &&
+ domain_name_list_contains(domain_names, realm))
+ return 1;
+ }
+#endif /* INTERWORKING_3GPP */
+
+ if (cred->domain == NULL)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
+ "home SP FQDN %s", cred->domain);
+ if (domain_name_list_contains(domain_names, cred->domain))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int interworking_find_network_match(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid;
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (wpas_network_disabled(wpa_s, ssid) ||
+ ssid->mode != WPAS_MODE_INFRA)
+ continue;
+ if (ssid->ssid_len != bss->ssid_len ||
+ os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) !=
+ 0)
+ continue;
+ /*
+ * TODO: Consider more accurate matching of security
+ * configuration similarly to what is done in events.c
+ */
+ return 1;
+ }
+ }
+
+ return 0;
}
static void interworking_select_network(struct wpa_supplicant *wpa_s)
{
- struct wpa_bss *bss, *selected = NULL;
+ struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
+ int selected_prio = -999999, selected_home_prio = -999999;
unsigned int count = 0;
+ const char *type;
+ int res;
+ struct wpa_cred *cred;
wpa_s->network_select = 0;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- if (!interworking_credentials_available(wpa_s, bss))
+ cred = interworking_credentials_available(wpa_s, bss);
+ if (!cred)
continue;
count++;
- wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR,
- MAC2STR(bss->bssid));
- if (selected == NULL && wpa_s->auto_select)
- selected = bss;
+ res = interworking_home_sp(wpa_s, bss->anqp_domain_name);
+ if (res > 0)
+ type = "home";
+ else if (res == 0)
+ type = "roaming";
+ else
+ type = "unknown";
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
+ MAC2STR(bss->bssid), type);
+ if (wpa_s->auto_select) {
+ if (selected == NULL ||
+ cred->priority > selected_prio) {
+ selected = bss;
+ selected_prio = cred->priority;
+ }
+ if (res > 0 &&
+ (selected_home == NULL ||
+ cred->priority > selected_home_prio)) {
+ selected_home = bss;
+ selected_home_prio = cred->priority;
+ }
+ }
+ }
+
+ if (selected_home && selected_home != selected &&
+ selected_home_prio >= selected_prio) {
+ /* Prefer network operated by the Home SP */
+ selected = selected_home;
}
if (count == 0) {
+ /*
+ * No matching network was found based on configured
+ * credentials. Check whether any of the enabled network blocks
+ * have matching APs.
+ */
+ if (interworking_find_network_match(wpa_s)) {
+ wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
+ "match for enabled network configurations");
+ interworking_reconnect(wpa_s);
+ return;
+ }
+
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
"with matching credentials found");
}
@@ -964,6 +1302,9 @@
{
const u8 *pos = data;
struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+#ifdef CONFIG_HS20
+ u8 type;
+#endif /* CONFIG_HS20 */
switch (info_id) {
case ANQP_CAPABILITY_LIST:
@@ -1047,6 +1388,28 @@
return;
switch (WPA_GET_BE24(pos)) {
+#ifdef CONFIG_HS20
+ case OUI_WFA:
+ pos += 3;
+ slen -= 3;
+
+ if (slen < 1)
+ return;
+ type = *pos++;
+ slen--;
+
+ switch (type) {
+ case HS20_ANQP_OUI_TYPE:
+ hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos,
+ slen);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
+ "vendor type %u", type);
+ break;
+ }
+ break;
+#endif /* CONFIG_HS20 */
default:
wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
"vendor-specific ANQP OUI %06x",
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index c124ca2..80aac77 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -61,6 +61,10 @@
#ifdef CONFIG_DEBUG_SYSLOG
printf(" -s = log output to syslog instead of stdout\n");
#endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ printf(" -T = record to Linux tracing in addition to logging\n");
+ printf(" (records all messages regardless of debug verbosity)\n");
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
printf(" -t = include timestamp in debug messages\n"
" -h = show this help text\n"
" -L = show license (BSD)\n"
@@ -139,7 +143,8 @@
wpa_supplicant_fd_workaround();
for (;;) {
- c = getopt(argc, argv, "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qstuvW");
+ c = getopt(argc, argv,
+ "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qsTtuvW");
if (c < 0)
break;
switch (c) {
@@ -214,6 +219,11 @@
params.wpa_debug_syslog++;
break;
#endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+ case 'T':
+ params.wpa_debug_tracing++;
+ break;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
case 't':
params.wpa_debug_timestamp++;
break;
@@ -252,6 +262,9 @@
wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");
exitcode = -1;
goto out;
+ } else {
+ wpa_printf(MSG_INFO, "Successfully initialized "
+ "wpa_supplicant");
}
for (i = 0; exitcode == 0 && i < iface_count; i++) {
diff --git a/wpa_supplicant/main_symbian.cpp b/wpa_supplicant/main_symbian.cpp
deleted file mode 100644
index 254fead..0000000
--- a/wpa_supplicant/main_symbian.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * WPA Supplicant / Program entrypoint for Symbian
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-extern "C" {
-#include "common.h"
-#include "wpa_supplicant_i.h"
-}
-
-GLDEF_C TInt E32Main(void)
-{
- struct wpa_interface iface;
- int exitcode = 0;
- struct wpa_params params;
- struct wpa_global *global;
-
- memset(¶ms, 0, sizeof(params));
- params.wpa_debug_level = MSG_INFO;
-
- global = wpa_supplicant_init(¶ms);
- if (global == NULL)
- return -1;
-
- memset(&iface, 0, sizeof(iface));
- /* TODO: set interface parameters */
-
- if (wpa_supplicant_add_iface(global, &iface) == NULL)
- exitcode = -1;
-
- if (exitcode == 0)
- exitcode = wpa_supplicant_run(global);
-
- wpa_supplicant_deinit(global);
-
- return exitcode;
-}
diff --git a/wpa_supplicant/nfc_pw_token.c b/wpa_supplicant/nfc_pw_token.c
new file mode 100644
index 0000000..11afb5b
--- /dev/null
+++ b/wpa_supplicant/nfc_pw_token.c
@@ -0,0 +1,83 @@
+/*
+ * nfc_pw_token - Tool for building NFC password tokens for WPS
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "crypto/random.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "wps_supplicant.h"
+
+
+static void print_bin(const char *title, const struct wpabuf *buf)
+{
+ size_t i, len;
+ const u8 *pos;
+
+ if (buf == NULL)
+ return;
+
+ printf("%s=", title);
+
+ pos = wpabuf_head(buf);
+ len = wpabuf_len(buf);
+ for (i = 0; i < len; i++)
+ printf("%02X", *pos++);
+
+ printf("\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct wpa_supplicant wpa_s;
+ int ret = -1;
+ struct wpabuf *buf = NULL, *ndef = NULL;
+ char txt[1000];
+
+ if (os_program_init())
+ return -1;
+ random_init(NULL);
+
+ os_memset(&wpa_s, 0, sizeof(wpa_s));
+ wpa_s.conf = os_zalloc(sizeof(*wpa_s.conf));
+ if (wpa_s.conf == NULL)
+ goto fail;
+
+ buf = wpas_wps_nfc_token(&wpa_s, 0);
+ if (buf == NULL)
+ goto fail;
+
+ ndef = ndef_build_wifi(buf);
+ if (ndef == NULL)
+ goto fail;
+
+ wpa_snprintf_hex_uppercase(txt, sizeof(txt), wpabuf_head(buf),
+ wpabuf_len(buf));
+ printf("#WPS=%s\n", txt);
+
+ wpa_snprintf_hex_uppercase(txt, sizeof(txt), wpabuf_head(ndef),
+ wpabuf_len(ndef));
+ printf("#NDEF=%s\n", txt);
+
+ printf("wps_nfc_dev_pw_id=%d\n", wpa_s.conf->wps_nfc_dev_pw_id);
+ print_bin("wps_nfc_dh_pubkey", wpa_s.conf->wps_nfc_dh_pubkey);
+ print_bin("wps_nfc_dh_privkey", wpa_s.conf->wps_nfc_dh_privkey);
+ print_bin("wps_nfc_dev_pw", wpa_s.conf->wps_nfc_dev_pw);
+
+ ret = 0;
+fail:
+ wpabuf_free(ndef);
+ wpabuf_free(buf);
+ wpa_config_free(wpa_s.conf);
+ random_deinit();
+ os_program_deinit();
+
+ return ret;
+}
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index f613897..59e6975 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -82,7 +82,7 @@
#ifdef CONFIG_P2P
if (new_state == WPA_COMPLETED)
wpas_p2p_notif_connected(wpa_s);
- else if (new_state < WPA_ASSOCIATED)
+ else if (old_state >= WPA_ASSOCIATED && new_state < WPA_ASSOCIATED)
wpas_p2p_notif_disconnected(wpa_s);
#endif /* CONFIG_P2P */
@@ -101,6 +101,12 @@
}
+void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
+{
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON);
+}
+
+
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
{
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK);
@@ -606,3 +612,20 @@
/* notify the new DBus API */
wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert);
}
+
+
+void wpas_notify_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len, u32 ssi_signal)
+{
+#ifdef CONFIG_AP
+ wpas_dbus_signal_preq(wpa_s, addr, dst, bssid, ie, ie_len, ssi_signal);
+#endif /* CONFIG_AP */
+}
+
+
+void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
+ const char *parameter)
+{
+ wpas_dbus_signal_eap_status(wpa_s, status, parameter);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index bd99a76..58675ac 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -22,6 +22,7 @@
void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
enum wpa_states new_state,
enum wpa_states old_state);
+void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
@@ -121,5 +122,10 @@
void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
const char *subject, const char *cert_hash,
const struct wpabuf *cert);
+void wpas_notify_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len, u32 ssi_signal);
+void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
+ const char *parameter);
#endif /* NOTIFY_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 5f1329e..e0c3580 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -39,6 +39,8 @@
*/
#define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
+#define P2P_AUTO_PD_SCAN_ATTEMPTS 5
+
#ifndef P2P_MAX_CLIENT_IDLE
/*
* How many seconds to try to reconnect to the GO when connection in P2P client
@@ -51,6 +53,14 @@
#endif /* ANDROID_P2P */
#endif /* P2P_MAX_CLIENT_IDLE */
+#ifndef P2P_MAX_INITIAL_CONN_WAIT
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * WPS provisioning step.
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT 10
+#endif /* P2P_MAX_INITIAL_CONN_WAIT */
+
#ifdef ANDROID_P2P
static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s);
#endif
@@ -59,15 +69,19 @@
wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
int go);
static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq);
static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
- const u8 *dev_addr, enum p2p_wps_method wps_method);
+ const u8 *dev_addr, enum p2p_wps_method wps_method,
+ int auto_join);
static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx,
void *timeout_ctx);
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+ int group_added);
#ifdef ANDROID_P2P
static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s)
@@ -112,7 +126,7 @@
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)
+ const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_driver_scan_params params;
@@ -120,7 +134,6 @@
struct wpabuf *wps_ie, *ies;
int social_channels[] = { 2412, 2437, 2462, 0, 0 };
size_t ielen;
- int was_in_p2p_scan;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -133,8 +146,8 @@
params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
wpa_s->wps->dev.p2p = 1;
- wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
- WPS_REQ_ENROLLEE,
+ 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;
@@ -160,34 +173,24 @@
break;
case P2P_SCAN_FULL:
break;
- case P2P_SCAN_SPECIFIC:
- social_channels[0] = freq;
- social_channels[1] = 0;
- params.freqs = social_channels;
- break;
case P2P_SCAN_SOCIAL_PLUS_ONE:
social_channels[3] = freq;
params.freqs = social_channels;
break;
}
- was_in_p2p_scan = wpa_s->scan_res_handler == wpas_p2p_scan_res_handler;
- wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
ret = wpa_drv_scan(wpa_s, ¶ms);
wpabuf_free(ies);
if (ret) {
- wpa_s->scan_res_handler = NULL;
-#ifdef ANDROID_P2P
- if (wpa_s->scanning || was_in_p2p_scan || wpas_global_scan_in_progress(wpa_s)) {
-#else
- if (wpa_s->scanning || was_in_p2p_scan) {
-#endif
+ if (wpa_s->scanning ||
+ wpa_s->scan_res_handler == wpas_p2p_scan_res_handler) {
wpa_s->p2p_cb_on_scan_complete = 1;
ret = 1;
}
- }
+ } else
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
return ret;
}
@@ -233,14 +236,12 @@
}
-static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
{
struct wpa_ssid *ssid;
char *gtype;
const char *reason;
- eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
-
ssid = wpa_s->current_ssid;
if (ssid == NULL) {
/*
@@ -283,6 +284,9 @@
case P2P_GROUP_REMOVAL_UNAVAILABLE:
reason = " reason=UNAVAILABLE";
break;
+ case P2P_GROUP_REMOVAL_GO_ENDING_SESSION:
+ reason = " reason=GO_ENDING_SESSION";
+ break;
#ifdef ANDROID_P2P
case P2P_GROUP_REMOVAL_FREQ_CONFLICT:
reason = " reason=FREQ_CONFLICT";
@@ -292,10 +296,16 @@
reason = "";
break;
}
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s",
- wpa_s->ifname, gtype, reason);
+ if (!silent) {
+ wpa_msg(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_REMOVED "%s %s%s",
+ wpa_s->ifname, gtype, reason);
+ }
- if (ssid)
+ if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
+
+ if (!silent && ssid)
wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
@@ -341,7 +351,10 @@
wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
"found");
}
- wpa_supplicant_ap_deinit(wpa_s);
+ if (wpa_s->ap_iface)
+ wpa_supplicant_ap_deinit(wpa_s);
+ else
+ wpa_drv_deinit_p2p_cli(wpa_s);
}
@@ -562,7 +575,7 @@
if (!success) {
wpa_msg(wpa_s->parent, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, 0);
return;
}
@@ -670,6 +683,13 @@
(os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
wpa_s->pending_pd_before_join = 0;
+ if (wpa_s->p2p_fallback_to_go_neg) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
+ "during p2p_connect-auto");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
"join-existing-group operation (no ACK for PD "
"Req)");
@@ -851,6 +871,8 @@
d->p2p_group_idle = s->p2p_group_idle;
d->p2p_intra_bss = s->p2p_intra_bss;
d->persistent_reconnect = s->persistent_reconnect;
+ d->max_num_sta = s->max_num_sta;
+ d->pbc_in_m1 = s->pbc_in_m1;
}
@@ -1002,6 +1024,20 @@
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
wpas_notify_p2p_go_neg_completed(wpa_s, res);
+ if (res->role_go && wpa_s->p2p_persistent_id >= 0) {
+ struct wpa_ssid *ssid;
+ ssid = wpa_config_get_network(wpa_s->conf,
+ wpa_s->p2p_persistent_id);
+ if (ssid && ssid->disabled == 2 &&
+ ssid->mode == WPAS_MODE_P2P_GO && ssid->passphrase) {
+ size_t len = os_strlen(ssid->passphrase);
+ wpa_printf(MSG_DEBUG, "P2P: Override passphrase based "
+ "on requested persistent group");
+ os_memcpy(res->passphrase, ssid->passphrase, len);
+ res->passphrase[len] = '\0';
+ }
+ }
+
if (wpa_s->create_p2p_iface) {
struct wpa_supplicant *group_wpa_s =
wpas_p2p_init_group_interface(wpa_s, res->role_go);
@@ -1836,6 +1872,7 @@
{
struct wpa_supplicant *wpa_s = ctx;
unsigned int generated_pin = 0;
+ char params[20];
if (wpa_s->pending_pd_before_join &&
(os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
@@ -1847,14 +1884,22 @@
return;
}
+ if (wpa_s->pending_pd_use == AUTO_PD_JOIN ||
+ wpa_s->pending_pd_use == AUTO_PD_GO_NEG)
+ os_snprintf(params, sizeof(params), " peer_go=%d",
+ wpa_s->pending_pd_use == AUTO_PD_JOIN);
+ else
+ params[0] = '\0';
+
if (config_methods & WPS_CONFIG_DISPLAY)
- wpas_prov_disc_local_keypad(wpa_s, peer, "");
+ wpas_prov_disc_local_keypad(wpa_s, peer, params);
else if (config_methods & WPS_CONFIG_KEYPAD) {
generated_pin = wps_generate_pin();
- wpas_prov_disc_local_display(wpa_s, peer, "", generated_pin);
+ wpas_prov_disc_local_display(wpa_s, peer, params,
+ generated_pin);
} else if (config_methods & WPS_CONFIG_PUSHBUTTON)
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR,
- MAC2STR(peer));
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR
+ "%s", MAC2STR(peer), params);
wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
P2P_PROV_DISC_SUCCESS,
@@ -1867,6 +1912,17 @@
{
struct wpa_supplicant *wpa_s = ctx;
+ if (wpa_s->p2p_fallback_to_go_neg) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto "
+ "failed - fall back to GO Negotiation");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+ return;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=%d",
+ MAC2STR(peer), status);
+
wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
status, 0, 0);
}
@@ -1993,7 +2049,7 @@
wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
} else if (bssid) {
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
- wpa_s->p2p_wps_method);
+ wpa_s->p2p_wps_method, 0);
}
return;
}
@@ -2061,6 +2117,31 @@
}
+static int wpas_p2p_disallowed_freq(struct wpa_global *global,
+ unsigned int freq)
+{
+ unsigned int i;
+
+ if (global->p2p_disallow_freq == NULL)
+ return 0;
+
+ for (i = 0; i < global->num_p2p_disallow_freq; i++) {
+ if (freq >= global->p2p_disallow_freq[i].min &&
+ freq <= global->p2p_disallow_freq[i].max)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan)
+{
+ reg->channel[reg->channels] = chan;
+ reg->channels++;
+}
+
+
static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
struct p2p_channels *chan)
{
@@ -2071,34 +2152,47 @@
/* Operating class 81 - 2.4 GHz band channels 1..13 */
chan->reg_class[cla].reg_class = 81;
- chan->reg_class[cla].channels = 11;
- for (i = 0; i < 11; i++)
- chan->reg_class[cla].channel[i] = i + 1;
- cla++;
+ chan->reg_class[cla].channels = 0;
+ for (i = 0; i < 11; i++) {
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 2412 + i * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], i + 1);
+ }
+ if (chan->reg_class[cla].channels)
+ cla++;
wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for lower 5 GHz "
"band");
/* Operating class 115 - 5 GHz, channels 36-48 */
chan->reg_class[cla].reg_class = 115;
- chan->reg_class[cla].channels = 4;
- chan->reg_class[cla].channel[0] = 36;
- chan->reg_class[cla].channel[1] = 40;
- chan->reg_class[cla].channel[2] = 44;
- chan->reg_class[cla].channel[3] = 48;
- cla++;
+ chan->reg_class[cla].channels = 0;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 36 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 36);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 40 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 40);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 44 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 44);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 48 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 48);
+ if (chan->reg_class[cla].channels)
+ cla++;
wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for higher 5 GHz "
"band");
/* Operating class 124 - 5 GHz, channels 149,153,157,161 */
chan->reg_class[cla].reg_class = 124;
- chan->reg_class[cla].channels = 4;
- chan->reg_class[cla].channel[0] = 149;
- chan->reg_class[cla].channel[1] = 153;
- chan->reg_class[cla].channel[2] = 157;
- chan->reg_class[cla].channel[3] = 161;
- cla++;
+ chan->reg_class[cla].channels = 0;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 149 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 149);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 153 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 153);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 156 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 157);
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 161 * 5))
+ wpas_p2p_add_chan(&chan->reg_class[cla], 161);
+ if (chan->reg_class[cla].channels)
+ cla++;
chan->reg_classes = cla;
return 0;
@@ -2120,9 +2214,16 @@
}
-static int has_channel(struct hostapd_hw_modes *mode, u8 chan, int *flags)
+static int has_channel(struct wpa_global *global,
+ struct hostapd_hw_modes *mode, u8 chan, int *flags)
{
int i;
+ unsigned int freq;
+
+ freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
+ chan * 5;
+ if (wpas_p2p_disallowed_freq(global, freq))
+ return 0;
for (i = 0; i < mode->num_channels; i++) {
if (mode->channels[i].chan == chan) {
@@ -2189,15 +2290,15 @@
continue;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
int flag;
- if (!has_channel(mode, ch, &flag))
+ if (!has_channel(wpa_s->global, mode, ch, &flag))
continue;
if (o->bw == BW40MINUS &&
(!(flag & HOSTAPD_CHAN_HT40MINUS) ||
- !has_channel(mode, ch - 4, NULL)))
+ !has_channel(wpa_s->global, mode, ch - 4, NULL)))
continue;
if (o->bw == BW40PLUS &&
(!(flag & HOSTAPD_CHAN_HT40PLUS) ||
- !has_channel(mode, ch + 4, NULL)))
+ !has_channel(wpa_s->global, mode, ch + 4, NULL)))
continue;
if (reg == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Add operating "
@@ -2404,6 +2505,7 @@
global->p2p = p2p_init(&p2p);
if (global->p2p == NULL)
return -1;
+ global->p2p_init_wpa_s = wpa_s;
for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
if (wpa_s->conf->wps_vendor_ext[i] == NULL)
@@ -2431,7 +2533,7 @@
/* Clear any stored provisioning info */
p2p_clear_provisioning_info(
wpa_s->global->p2p,
- wpa_s->go_params->peer_interface_addr);
+ wpa_s->go_params->peer_device_addr);
}
os_free(wpa_s->go_params);
@@ -2458,7 +2560,6 @@
void wpas_p2p_deinit_global(struct wpa_global *global)
{
struct wpa_supplicant *wpa_s, *tmp;
- char *ifname;
if (global->p2p == NULL)
return;
@@ -2470,7 +2571,6 @@
while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
wpa_s = wpa_s->next;
while (wpa_s) {
- enum wpa_driver_if_type type;
tmp = global->ifaces;
while (tmp &&
(tmp == wpa_s ||
@@ -2479,12 +2579,8 @@
}
if (tmp == NULL)
break;
- ifname = os_strdup(tmp->ifname);
- type = wpas_p2p_if_type(tmp->p2p_group_interface);
- wpa_supplicant_remove_iface(global, tmp, 0);
- if (ifname)
- wpa_drv_if_remove(wpa_s, type, ifname);
- os_free(ifname);
+ /* Disconnect from the P2P group and deinit the interface */
+ wpas_p2p_disconnect(tmp);
}
/*
@@ -2498,6 +2594,7 @@
p2p_deinit(global->p2p);
global->p2p = NULL;
+ global->p2p_init_wpa_s = NULL;
}
@@ -2522,7 +2619,8 @@
const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
- unsigned int force_freq, int persistent_group)
+ unsigned int force_freq, int persistent_group,
+ struct wpa_ssid *ssid)
{
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
@@ -2535,7 +2633,9 @@
return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
- persistent_group);
+ persistent_group, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0,
+ wpa_s->p2p_pd_before_go_neg);
}
@@ -2543,7 +2643,8 @@
const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
- unsigned int force_freq, int persistent_group)
+ unsigned int force_freq, int persistent_group,
+ struct wpa_ssid *ssid)
{
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
@@ -2553,7 +2654,8 @@
return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
- persistent_group);
+ persistent_group, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0);
}
@@ -2567,6 +2669,13 @@
" for join operationg - stop join attempt",
MAC2STR(wpa_s->pending_join_iface_addr));
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+ if (wpa_s->p2p_auto_pd) {
+ wpa_s->p2p_auto_pd = 0;
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=N/A",
+ MAC2STR(wpa_s->pending_join_dev_addr));
+ return;
+ }
wpa_msg(wpa_s->parent, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
}
@@ -2588,26 +2697,155 @@
}
+static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
+{
+ struct wpa_supplicant *iface;
+ int shared_freq;
+ u8 bssid[ETH_ALEN];
+
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
+ return 0;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ if (!wpas_p2p_create_iface(wpa_s) && iface == wpa_s)
+ continue;
+ if (iface->current_ssid == NULL || iface->assoc_freq == 0)
+ continue;
+ if (iface->current_ssid->mode == WPAS_MODE_AP ||
+ iface->current_ssid->mode == WPAS_MODE_P2P_GO)
+ shared_freq = iface->current_ssid->frequency;
+ else if (wpa_drv_get_bssid(iface, bssid) == 0)
+ shared_freq = iface->assoc_freq;
+ else
+ shared_freq = 0;
+
+ if (shared_freq && freq != shared_freq) {
+ wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - %s "
+ "connected on %d MHz - new connection on "
+ "%d MHz", iface->ifname, shared_freq, freq);
+ return 1;
+ }
+ }
+
+ shared_freq = wpa_drv_shared_freq(wpa_s);
+ if (shared_freq > 0 && shared_freq != freq) {
+ wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - shared "
+ "virtual interface connected on %d MHz - new "
+ "connection on %d MHz", shared_freq, freq);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s,
+ const u8 *peer_dev_addr)
+{
+ struct wpa_bss *bss;
+ int updated;
+
+ bss = wpa_bss_get_p2p_dev_addr(wpa_s, peer_dev_addr);
+ if (bss == NULL)
+ return -1;
+ if (bss->last_update_idx < wpa_s->bss_update_idx) {
+ wpa_printf(MSG_DEBUG, "P2P: Peer BSS entry not updated in the "
+ "last scan");
+ return 0;
+ }
+
+ updated = os_time_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,
+ updated ? "": "not ");
+
+ return updated;
+}
+
+
static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
struct wpa_bss *bss;
int freq;
u8 iface_addr[ETH_ALEN];
-#ifdef ANDROID_P2P
- int shared_freq = 0;
-#endif
+
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
if (wpa_s->global->p2p_disabled)
return;
- wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for join",
- scan_res ? (int) scan_res->num : -1);
+ wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for %sjoin",
+ scan_res ? (int) scan_res->num : -1,
+ wpa_s->p2p_auto_join ? "auto_" : "");
if (scan_res)
wpas_p2p_scan_res_handler(wpa_s, scan_res);
+ if (wpa_s->p2p_auto_pd) {
+ int join = wpas_p2p_peer_go(wpa_s,
+ wpa_s->pending_join_dev_addr);
+ if (join == 0 &&
+ wpa_s->auto_pd_scan_retry < P2P_AUTO_PD_SCAN_ATTEMPTS) {
+ wpa_s->auto_pd_scan_retry++;
+ bss = wpa_bss_get_bssid(wpa_s,
+ wpa_s->pending_join_dev_addr);
+ if (bss) {
+ freq = bss->freq;
+ wpa_printf(MSG_DEBUG, "P2P: Scan retry %d for "
+ "the peer " MACSTR " at %d MHz",
+ wpa_s->auto_pd_scan_retry,
+ MAC2STR(wpa_s->
+ pending_join_dev_addr),
+ freq);
+ wpas_p2p_join_scan_req(wpa_s, freq);
+ return;
+ }
+ }
+
+ if (join < 0)
+ join = 0;
+
+ wpa_s->p2p_auto_pd = 0;
+ wpa_s->pending_pd_use = join ? AUTO_PD_JOIN : AUTO_PD_GO_NEG;
+ wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d",
+ MAC2STR(wpa_s->pending_join_dev_addr), join);
+ if (p2p_prov_disc_req(wpa_s->global->p2p,
+ wpa_s->pending_join_dev_addr,
+ wpa_s->pending_pd_config_methods, join,
+ 0) < 0) {
+ wpa_s->p2p_auto_pd = 0;
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=N/A",
+ MAC2STR(wpa_s->pending_join_dev_addr));
+ }
+ return;
+ }
+
+ if (wpa_s->p2p_auto_join) {
+ int join = wpas_p2p_peer_go(wpa_s,
+ wpa_s->pending_join_dev_addr);
+ if (join < 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
+ "running a GO -> use GO Negotiation");
+ wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr,
+ wpa_s->p2p_pin, wpa_s->p2p_wps_method,
+ wpa_s->p2p_persistent_group, 0, 0, 0,
+ wpa_s->p2p_go_intent,
+ wpa_s->p2p_connect_freq,
+ wpa_s->p2p_persistent_id,
+ wpa_s->p2p_pd_before_go_neg);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> "
+ "try to join the group", join ? "" :
+ " in older scan");
+ if (!join)
+ wpa_s->p2p_fallback_to_go_neg = 1;
+ }
+
freq = p2p_get_oper_freq(wpa_s->global->p2p,
wpa_s->pending_join_iface_addr);
if (freq < 0 &&
@@ -2631,16 +2869,6 @@
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
"from P2P peer table: %d MHz", freq);
}
-
-#ifdef ANDROID_P2P
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
- ((shared_freq = wpa_drv_shared_freq(wpa_s)) > 0) && (shared_freq != freq)) {
- wpa_msg(wpa_s->parent, MSG_INFO,
- P2P_EVENT_GROUP_FORMATION_FAILURE "reason=FREQ_CONFLICT");
- return;
- }
-#endif
-
bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
if (bss) {
freq = bss->freq;
@@ -2650,6 +2878,13 @@
if (freq > 0) {
u16 method;
+ if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
+ wpa_msg(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_FORMATION_FAILURE
+ "reason=FREQ_CONFLICT");
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request "
"prior to joining an existing group (GO " MACSTR
" freq=%u MHz)",
@@ -2722,13 +2957,13 @@
}
-static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
int ret;
struct wpa_driver_scan_params params;
struct wpabuf *wps_ie, *ies;
size_t ielen;
+ int freqs[2] = { 0, 0 };
os_memset(¶ms, 0, sizeof(params));
@@ -2738,8 +2973,9 @@
params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
wpa_s->wps->dev.p2p = 1;
- wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
- WPS_REQ_ENROLLEE, 0, NULL);
+ wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev,
+ wpa_s->wps->uuid, WPS_REQ_ENROLLEE, 0,
+ NULL);
if (wps_ie == NULL) {
wpas_p2p_scan_res_join(wpa_s, NULL);
return;
@@ -2760,13 +2996,18 @@
params.p2p_probe = 1;
params.extra_ies = wpabuf_head(ies);
params.extra_ies_len = wpabuf_len(ies);
+ if (freq > 0) {
+ freqs[0] = freq;
+ params.freqs = freqs;
+ }
/*
* Run a scan to update BSS table and start Provision Discovery once
* the new scan results become available.
*/
- wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
ret = wpa_drv_scan(wpa_s, ¶ms);
+ if (!ret)
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
wpabuf_free(ies);
@@ -2780,13 +3021,24 @@
}
+static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpas_p2p_join_scan_req(wpa_s, 0);
+}
+
+
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
- const u8 *dev_addr, enum p2p_wps_method wps_method)
+ const u8 *dev_addr, enum p2p_wps_method wps_method,
+ int auto_join)
{
wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
- MACSTR " dev " MACSTR ")",
- MAC2STR(iface_addr), MAC2STR(dev_addr));
+ MACSTR " dev " MACSTR ")%s",
+ MAC2STR(iface_addr), MAC2STR(dev_addr),
+ auto_join ? " (auto_join)" : "");
+ wpa_s->p2p_auto_pd = 0;
+ wpa_s->p2p_auto_join = !!auto_join;
os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN);
os_memcpy(wpa_s->pending_join_dev_addr, dev_addr, ETH_ALEN);
wpa_s->pending_join_wps_method = wps_method;
@@ -2804,6 +3056,7 @@
{
struct wpa_supplicant *group;
struct p2p_go_neg_results res;
+ struct wpa_bss *bss;
eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
group = wpas_p2p_get_group_iface(wpa_s, 0, 0);
@@ -2816,11 +3069,19 @@
}
group->p2p_in_provisioning = 1;
+ group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
os_memset(&res, 0, sizeof(res));
os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
ETH_ALEN);
res.wps_method = wpa_s->pending_join_wps_method;
+ bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+ if (bss) {
+ res.freq = bss->freq;
+ res.ssid_len = bss->ssid_len;
+ os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+ }
+
if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel prior to "
"starting client");
@@ -2849,30 +3110,43 @@
* @peer_addr: Address of the peer P2P Device
* @pin: PIN to use during provisioning or %NULL to indicate PBC mode
* @persistent_group: Whether to create a persistent group
+ * @auto_join: Whether to select join vs. GO Negotiation automatically
* @join: Whether to join an existing group (as a client) instead of starting
* Group Owner negotiation; @peer_addr is BSSID in that case
* @auth: Whether to only authorize the connection instead of doing that and
* initiating Group Owner negotiation
* @go_intent: GO Intent or -1 to use default
* @freq: Frequency for the group or 0 for auto-selection
+ * @persistent_id: Persistent group credentials to use for forcing GO
+ * parameters or -1 to generate new values (SSID/passphrase)
+ * @pd: Whether to send Provision Discovery prior to GO Negotiation as an
+ * interoperability workaround when initiating group formation
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
* failure, -2 on failure due to channel not currently available,
* -3 if forced channel is not supported
*/
int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
- int persistent_group, int join, int auth, int go_intent,
- int freq)
+ int persistent_group, int auto_join, int join, int auth,
+ int go_intent, int freq, int persistent_id, int pd)
{
int force_freq = 0, oper_freq = 0;
u8 bssid[ETH_ALEN];
int ret = 0;
enum wpa_driver_if_type iftype;
const u8 *if_addr;
+ struct wpa_ssid *ssid = NULL;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (persistent_id >= 0) {
+ ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
+ if (ssid == NULL || ssid->disabled != 2 ||
+ ssid->mode != WPAS_MODE_P2P_GO)
+ return -1;
+ }
+
if (go_intent < 0)
go_intent = wpa_s->conf->p2p_go_intent;
@@ -2880,6 +3154,12 @@
wpa_s->p2p_long_listen = 0;
wpa_s->p2p_wps_method = wps_method;
+ wpa_s->p2p_persistent_group = !!persistent_group;
+ wpa_s->p2p_persistent_id = persistent_id;
+ wpa_s->p2p_go_intent = go_intent;
+ wpa_s->p2p_connect_freq = freq;
+ wpa_s->p2p_fallback_to_go_neg = 0;
+ wpa_s->p2p_pd_before_go_neg = !!pd;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -2892,7 +3172,7 @@
} else
wpa_s->p2p_pin[0] = '\0';
- if (join) {
+ if (join || auto_join) {
u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
if (auth) {
wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
@@ -2908,8 +3188,15 @@
p2p_get_dev_addr(wpa_s->global->p2p, peer_addr,
dev_addr);
}
- if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method) <
- 0)
+ if (auto_join) {
+ os_get_time(&wpa_s->p2p_auto_started);
+ wpa_printf(MSG_DEBUG, "P2P: Auto join started at "
+ "%ld.%06ld",
+ wpa_s->p2p_auto_started.sec,
+ wpa_s->p2p_auto_started.usec);
+ }
+ if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
+ auto_join) < 0)
return -1;
return ret;
}
@@ -2982,14 +3269,15 @@
if (auth) {
if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
go_intent, if_addr,
- force_freq, persistent_group) < 0)
+ force_freq, persistent_group, ssid) <
+ 0)
return -1;
return ret;
}
if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
go_intent, if_addr, force_freq,
- persistent_group) < 0) {
+ persistent_group, ssid) < 0) {
if (wpa_s->create_p2p_iface)
wpas_p2p_remove_pending_group_interface(wpa_s);
return -1;
@@ -3147,7 +3435,18 @@
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
"channel %d MHz", params->freq);
} else {
- params->freq = 2412;
+ int chan;
+ for (chan = 0; chan < 11; chan++) {
+ params->freq = 2412 + chan * 5;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global,
+ params->freq))
+ break;
+ }
+ if (chan == 11) {
+ wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel "
+ "allowed");
+ return -1;
+ }
wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
"known)", params->freq);
}
@@ -3270,6 +3569,13 @@
if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq))
return -1;
+ if (params.freq &&
+ !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
+ "(%u MHz) is not supported for P2P uses",
+ params.freq);
+ return -1;
+ }
p2p_go_params(wpa_s->global->p2p, ¶ms);
params.persistent_group = persistent_group;
@@ -3346,6 +3652,8 @@
/* Make sure we are not running find during connection establishment */
wpas_p2p_stop_find(wpa_s);
+ wpa_s->p2p_fallback_to_go_neg = 0;
+
if (ssid->mode == WPAS_MODE_INFRA)
return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
@@ -3409,18 +3717,15 @@
if (!wpa_s->ap_iface)
return;
wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not ");
- if (idle) {
- wpa_printf(MSG_DEBUG,"Calling set group idle time out from idle_update");
+ if (idle)
wpas_p2p_set_group_idle_timeout(wpa_s);
- }
else
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
}
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
- int persistent_group,
- int group_formation)
+ struct wpa_ssid *ssid)
{
struct p2p_group *group;
struct p2p_group_config *cfg;
@@ -3434,9 +3739,9 @@
if (cfg == NULL)
return NULL;
- if (persistent_group && wpa_s->conf->persistent_reconnect)
+ if (ssid->p2p_persistent_group && wpa_s->conf->persistent_reconnect)
cfg->persistent_group = 2;
- else if (persistent_group)
+ else if (ssid->p2p_persistent_group)
cfg->persistent_group = 1;
os_memcpy(cfg->interface_addr, wpa_s->own_addr, ETH_ALEN);
if (wpa_s->max_stations &&
@@ -3444,6 +3749,8 @@
cfg->max_clients = wpa_s->max_stations;
else
cfg->max_clients = wpa_s->conf->max_num_sta;
+ os_memcpy(cfg->ssid, ssid->ssid, ssid->ssid_len);
+ cfg->ssid_len = ssid->ssid_len;
cfg->cb_ctx = wpa_s;
cfg->ie_update = wpas_p2p_ie_update;
cfg->idle_update = wpas_p2p_idle_update;
@@ -3451,7 +3758,7 @@
group = p2p_group_init(wpa_s->global->p2p, cfg);
if (group == NULL)
os_free(cfg);
- if (!group_formation)
+ if (ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
p2p_group_notif_formation_done(group);
wpa_s->p2p_group = group;
return group;
@@ -3461,17 +3768,36 @@
void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
int registrar)
{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
if (!wpa_s->p2p_in_provisioning) {
wpa_printf(MSG_DEBUG, "P2P: Ignore WPS success event - P2P "
"provisioning not in progress");
return;
}
- /* Clear any stored provisioning info */
- p2p_clear_provisioning_info(wpa_s->global->p2p, peer_addr);
+ if (ssid && ssid->mode == WPAS_MODE_INFRA) {
+ u8 go_dev_addr[ETH_ALEN];
+ os_memcpy(go_dev_addr, wpa_s->bssid, ETH_ALEN);
+ wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid,
+ ssid->ssid_len);
+ /* Clear any stored provisioning info */
+ p2p_clear_provisioning_info(wpa_s->global->p2p, go_dev_addr);
+ }
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
NULL);
+ if (ssid && ssid->mode == WPAS_MODE_INFRA) {
+ /*
+ * Use a separate timeout for initial data connection to
+ * complete to allow the group to be removed automatically if
+ * something goes wrong in this step before the P2P group idle
+ * timeout mechanism is taken into use.
+ */
+ eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ }
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)
@@ -3492,7 +3818,7 @@
if (wpa_s->go_params) {
p2p_clear_provisioning_info(
wpa_s->global->p2p,
- wpa_s->go_params->peer_interface_addr);
+ wpa_s->go_params->peer_device_addr);
}
wpas_notify_p2p_wps_failed(wpa_s, fail);
@@ -3500,10 +3826,13 @@
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
- const char *config_method, int join)
+ const char *config_method,
+ enum wpas_p2p_prov_disc_use use)
{
u16 config_methods;
+ wpa_s->p2p_fallback_to_go_neg = 0;
+ wpa_s->pending_pd_use = NORMAL_PD;
if (os_strncmp(config_method, "display", 7) == 0)
config_methods = WPS_CONFIG_DISPLAY;
else if (os_strncmp(config_method, "keypad", 6) == 0)
@@ -3516,16 +3845,35 @@
return -1;
}
+ if (use == WPAS_P2P_PD_AUTO) {
+ os_memcpy(wpa_s->pending_join_dev_addr, peer_addr, ETH_ALEN);
+ wpa_s->pending_pd_config_methods = config_methods;
+ wpa_s->p2p_auto_pd = 1;
+ wpa_s->p2p_auto_join = 0;
+ wpa_s->pending_pd_before_join = 0;
+ 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);
+ wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld",
+ wpa_s->p2p_auto_started.sec,
+ wpa_s->p2p_auto_started.usec);
+ wpas_p2p_join_scan(wpa_s, NULL);
+ 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, join);
+ config_methods,
+ use == WPAS_P2P_PD_FOR_JOIN);
}
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
return -1;
return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
- config_methods, join, 0);
+ config_methods, use == WPAS_P2P_PD_FOR_JOIN,
+ 0);
}
@@ -3559,7 +3907,8 @@
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)
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
+ wpa_s->p2p_in_provisioning)
return -1;
wpa_supplicant_cancel_sched_scan(wpa_s);
@@ -3661,15 +4010,27 @@
int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
const u8 *dst, const u8 *bssid,
- const u8 *ie, size_t ie_len)
+ const u8 *ie, size_t ie_len, int ssi_signal)
{
if (wpa_s->global->p2p_disabled)
return 0;
if (wpa_s->global->p2p == NULL)
return 0;
- return p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
- ie, ie_len);
+ switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
+ ie, ie_len)) {
+ case P2P_PREQ_NOT_P2P:
+ wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
+ ssi_signal);
+ /* fall through */
+ case P2P_PREQ_MALFORMED:
+ case P2P_PREQ_NOT_LISTEN:
+ case P2P_PREQ_NOT_PROCESSED:
+ default: /* make gcc happy */
+ return 0;
+ case P2P_PREQ_PROCESSED:
+ return 1;
+ }
}
@@ -3840,6 +4201,11 @@
int persistent;
int freq;
+ if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ }
+
if (!wpa_s->show_group_started || !ssid)
return;
@@ -3936,18 +4302,20 @@
return;
}
- wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate %d"
- "group",wpa_s->conf->p2p_group_idle);
+ wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
+ "group");
wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT;
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, 0);
}
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
{
- unsigned int timeout;
+ int timeout;
- eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
+ if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
+
if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
return;
@@ -3959,6 +4327,37 @@
if (timeout == 0)
return;
+ if (timeout < 0) {
+ if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA)
+ timeout = 0; /* special client mode no-timeout */
+ else
+ return;
+ }
+
+ if (wpa_s->p2p_in_provisioning) {
+ /*
+ * Use the normal group formation timeout during the
+ * provisioning phase to avoid terminating this process too
+ * early due to group idle timeout.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout "
+ "during provisioning");
+ return;
+ }
+
+ if (wpa_s->show_group_started) {
+ /*
+ * Use the normal group formation timeout between the end of
+ * the provisioning phase and completion of 4-way handshake to
+ * avoid terminating this process too early due to group idle
+ * timeout.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout "
+ "while waiting for initial 4-way handshake to "
+ "complete");
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds",
timeout);
eloop_register_timeout(timeout, 0, wpas_p2p_group_idle_timeout,
@@ -3967,26 +4366,42 @@
void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len)
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated)
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
return;
- p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
+ if (!locally_generated)
+ p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie,
+ ie_len);
+
+ if (reason_code == WLAN_REASON_DEAUTH_LEAVING && !locally_generated &&
+ wpa_s->current_ssid &&
+ wpa_s->current_ssid->p2p_group &&
+ wpa_s->current_ssid->mode == WPAS_MODE_INFRA) {
+ wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group "
+ "session is ending");
+ wpa_s->removal_reason = P2P_GROUP_REMOVAL_GO_ENDING_SESSION;
+ wpas_p2p_group_delete(wpa_s, 0);
+ }
}
void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len)
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated)
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
return;
- p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
+ if (!locally_generated)
+ p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie,
+ ie_len);
}
@@ -4102,6 +4517,14 @@
wpa_printf(MSG_ERROR, "P2P: Own oper channel update "
"failed: %d", ret);
}
+
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_PREF_CHAN) {
+ if (p2p_set_pref_chan(p2p, wpa_s->conf->num_p2p_pref_chan,
+ wpa_s->conf->p2p_pref_chan) < 0) {
+ wpa_printf(MSG_ERROR, "P2P: Preferred channel list "
+ "update failed");
+ }
+ }
}
@@ -4200,8 +4623,9 @@
wpas_p2p_disable_cross_connect(wpa_s);
else
wpas_p2p_enable_cross_connect(wpa_s);
- if (!wpa_s->ap_iface)
- eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
+ if (!wpa_s->ap_iface &&
+ eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
}
@@ -4211,10 +4635,7 @@
if (!wpa_s->ap_iface &&
!eloop_is_timeout_registered(wpas_p2p_group_idle_timeout,
wpa_s, NULL))
- {
- wpa_printf(MSG_DEBUG,"Calling set grouple idle_timeout from notif_disconnected");
wpas_p2p_set_group_idle_timeout(wpa_s);
- }
}
@@ -4316,6 +4737,7 @@
wpa_printf(MSG_DEBUG, "P2P: Unauthorize pending GO Neg peer "
MACSTR, MAC2STR(peer));
p2p_unauthorize(global->p2p, peer);
+ found = 1;
}
wpas_p2p_stop_find(wpa_s);
@@ -4331,7 +4753,7 @@
found = 1;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->parent, NULL);
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, 0);
break;
}
}
@@ -4353,7 +4775,7 @@
wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not "
"being available anymore");
wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, 0);
}
@@ -4400,7 +4822,7 @@
return -1;
wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
- wpas_p2p_group_delete(wpa_s);
+ wpas_p2p_group_delete(wpa_s, 0);
return 0;
}
@@ -4417,20 +4839,22 @@
void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
-
{
if (wpa_s->p2p_in_provisioning && ssid->p2p_group &&
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->parent, NULL) > 0) {
+ /**
+ * Remove the network by scheduling the group formation
+ * timeout to happen immediately. The teardown code
+ * needs to be scheduled to run asynch later so that we
+ * don't delete data from under ourselves unexpectedly.
+ * Calling wpas_p2p_group_formation_timeout directly
+ * causes a series of crashes in WPS failure scenarios.
+ */
wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to "
"P2P group network getting removed");
-#ifdef ANDROID_P2P
- /* Give time for any Pending WPS Frame exchange */
- eloop_register_timeout(5, 0, wpas_p2p_group_formation_timeout,
- wpa_s->parent, NULL);
-#else
- wpas_p2p_group_formation_timeout(wpa_s->parent, NULL);
-#endif
+ eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
}
}
@@ -4473,6 +4897,43 @@
wpas_p2p_add_persistent_group_client(wpa_s, addr);
}
+
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+ int group_added)
+{
+ struct wpa_supplicant *group = wpa_s;
+ eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
+ if (wpa_s->global->p2p_group_formation)
+ group = wpa_s->global->p2p_group_formation;
+ wpa_s = wpa_s->parent;
+ offchannel_send_action_done(wpa_s);
+ if (group_added)
+ wpas_p2p_group_delete(group, 1);
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation");
+ wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
+ wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
+ 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
+ wpa_s->p2p_persistent_id,
+ wpa_s->p2p_pd_before_go_neg);
+}
+
+
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->p2p_fallback_to_go_neg ||
+ wpa_s->p2p_in_provisioning <= 5)
+ return 0;
+
+ if (wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr) > 0)
+ return 0; /* peer operating as a GO */
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
+ "fallback to GO Negotiation");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 1);
+
+ return 1;
+}
+
#ifdef ANDROID_P2P
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
{
@@ -4503,7 +4964,7 @@
wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
"concurrent mode frequency conflict");
iface->removal_reason = P2P_GROUP_REMOVAL_FREQ_CONFLICT;
- wpas_p2p_group_delete(iface);
+ wpas_p2p_group_delete(iface, 0);
} else {
/* Existing connection has the priority. Disable the newly
* selected network and let the application know about it.
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 05c648a..24fb81e 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -19,8 +19,9 @@
void wpas_p2p_deinit_global(struct wpa_global *global);
int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
- int persistent_group, int join, int auth, int go_intent,
- int freq);
+ int persistent_group, int auto_join, int join,
+ int auth, int go_intent, int freq, int persistent_id,
+ int pd);
void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq, unsigned int duration);
void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
@@ -36,12 +37,17 @@
struct wpa_ssid *ssid, int addr_allocated,
int freq);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
- int persistent_group,
- int group_formation);
+ struct wpa_ssid *ssid);
void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
int registrar);
+enum wpas_p2p_prov_disc_use {
+ WPAS_P2P_PD_FOR_GO_NEG,
+ WPAS_P2P_PD_FOR_JOIN,
+ WPAS_P2P_PD_AUTO
+};
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
- const char *config_method, int join);
+ const char *config_method,
+ enum wpas_p2p_prov_disc_use use);
void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
const u8 *data, size_t data_len,
enum p2p_send_action_result result);
@@ -58,7 +64,8 @@
u8 *buf, size_t len, int p2p_group);
int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
const u8 *dst, const u8 *bssid,
- const u8 *ie, size_t ie_len);
+ const u8 *ie, size_t ie_len,
+ int ssi_signal);
void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
const u8 *sa, const u8 *bssid,
u8 category, const u8 *data, size_t len, int freq);
@@ -108,9 +115,11 @@
int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
unsigned int interval);
void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len);
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated);
void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len);
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated);
void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
int duration);
@@ -135,5 +144,6 @@
size_t ssid_len);
void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr);
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
#endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 5aee7ff..8df21d9 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -17,6 +17,7 @@
#include "wps_supplicant.h"
#include "p2p_supplicant.h"
#include "p2p/p2p.h"
+#include "hs20_supplicant.h"
#include "notify.h"
#include "bss.h"
#include "scan.h"
@@ -79,12 +80,12 @@
#endif /* CONFIG_WPS */
-int wpa_supplicant_enabled_networks(struct wpa_config *conf)
+int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s)
{
- struct wpa_ssid *ssid = conf->ssid;
+ struct wpa_ssid *ssid = wpa_s->conf->ssid;
int count = 0;
while (ssid) {
- if (!ssid->disabled)
+ if (!wpas_network_disabled(wpa_s, ssid))
count++;
ssid = ssid->next;
}
@@ -96,7 +97,7 @@
struct wpa_ssid *ssid)
{
while (ssid) {
- if (!ssid->disabled)
+ if (!wpas_network_disabled(wpa_s, ssid))
break;
ssid = ssid->next;
}
@@ -405,7 +406,9 @@
if (wps) {
struct wpabuf *wps_ie;
- wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
+ wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON :
+ DEV_PW_DEFAULT,
+ &wpa_s->wps->dev,
wpa_s->wps->uuid, req_type,
0, NULL);
if (wps_ie) {
@@ -434,8 +437,9 @@
struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_ssid *ssid;
int scan_req = 0, ret;
- struct wpabuf *extra_ie;
+ struct wpabuf *extra_ie = NULL;
struct wpa_driver_scan_params params;
+ struct wpa_driver_scan_params *scan_params;
size_t max_ssids;
enum wpa_states prev_state;
@@ -449,7 +453,7 @@
return;
}
- if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
+ if (!wpa_supplicant_enabled_networks(wpa_s) &&
!wpa_s->scan_req) {
wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
@@ -501,6 +505,14 @@
wpa_s->wpa_state == WPA_INACTIVE)
wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
+ /*
+ * If autoscan has set its own scanning parameters
+ */
+ if (wpa_s->autoscan_params != NULL) {
+ scan_params = wpa_s->autoscan_params;
+ goto scan;
+ }
+
if (scan_req != 2 && wpa_s->connect_without_scan) {
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (ssid == wpa_s->connect_without_scan)
@@ -515,6 +527,18 @@
}
}
+#ifdef CONFIG_P2P
+ if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
+ wpa_s->go_params) {
+ wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during "
+ "P2P group formation");
+ params.ssids[0].ssid = wpa_s->go_params->ssid;
+ params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
+ params.num_ssids = 1;
+ goto ssid_list_set;
+ }
+#endif /* CONFIG_P2P */
+
/* Find the starting point from which to continue scanning */
ssid = wpa_s->conf->ssid;
if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
@@ -546,7 +570,8 @@
if (ssid == NULL && max_ssids > 1)
ssid = wpa_s->conf->ssid;
while (ssid) {
- if (!ssid->disabled && ssid->scan_ssid) {
+ if (!wpas_network_disabled(wpa_s, ssid) &&
+ ssid->scan_ssid) {
wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
ssid->ssid, ssid->ssid_len);
params.ssids[params.num_ssids].ssid =
@@ -566,7 +591,7 @@
}
for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
- if (tssid->disabled)
+ if (wpas_network_disabled(wpa_s, tssid))
continue;
if ((params.freqs || !freqs_set) && tssid->scan_freq) {
int_array_concat(¶ms.freqs,
@@ -612,10 +637,18 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
"SSID");
}
+#ifdef CONFIG_P2P
+ssid_list_set:
+#endif /* CONFIG_P2P */
wpa_supplicant_optimize_freqs(wpa_s, ¶ms);
extra_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms);
+#ifdef CONFIG_HS20
+ if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0)
+ wpas_hs20_add_indication(extra_ie);
+#endif /* CONFIG_HS20 */
+
if (params.freqs == NULL && wpa_s->next_scan_freqs) {
wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
"generated frequency list");
@@ -632,7 +665,8 @@
}
#ifdef CONFIG_P2P
- if (wpa_s->p2p_in_provisioning) {
+ if (wpa_s->p2p_in_provisioning ||
+ (wpa_s->show_group_started && wpa_s->go_params)) {
/*
* The interface may not yet be in P2P mode, so we have to
* explicitly request P2P probe to disable CCK rates.
@@ -641,7 +675,10 @@
}
#endif /* CONFIG_P2P */
- ret = wpa_supplicant_trigger_scan(wpa_s, ¶ms);
+ scan_params = ¶ms;
+
+scan:
+ ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
wpabuf_free(extra_ie);
os_free(params.freqs);
@@ -679,7 +716,8 @@
struct wpa_ssid *ssid = wpa_s->conf->ssid;
while (ssid) {
- if (!ssid->disabled && ssid->scan_ssid)
+ if (!wpas_network_disabled(wpa_s, ssid) &&
+ ssid->scan_ssid)
break;
ssid = ssid->next;
}
@@ -730,8 +768,9 @@
int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
{
struct wpa_driver_scan_params params;
+ struct wpa_driver_scan_params *scan_params;
enum wpa_states prev_state;
- struct wpa_ssid *ssid;
+ struct wpa_ssid *ssid = NULL;
struct wpabuf *wps_ie = NULL;
int ret;
unsigned int max_sched_scan_ssids;
@@ -745,7 +784,7 @@
max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
else
max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
- if (max_sched_scan_ssids < 1)
+ if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload)
return -1;
if (wpa_s->sched_scanning) {
@@ -755,11 +794,27 @@
need_ssids = 0;
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
- if (!ssid->disabled && !ssid->scan_ssid) {
+ if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) {
/* Use wildcard SSID to find this network */
wildcard = 1;
- } else if (!ssid->disabled && ssid->ssid_len)
+ } else if (!wpas_network_disabled(wpa_s, ssid) &&
+ ssid->ssid_len)
need_ssids++;
+
+#ifdef CONFIG_WPS
+ if (!wpas_network_disabled(wpa_s, ssid) &&
+ ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
+ /*
+ * Normal scan is more reliable and faster for WPS
+ * operations and since these are for short periods of
+ * time, the benefit of trying to use sched_scan would
+ * be limited.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
+ "sched_scan for WPS");
+ return -1;
+ }
+#endif /* CONFIG_WPS */
}
if (wildcard)
need_ssids++;
@@ -793,6 +848,11 @@
wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
#endif
+ if (wpa_s->autoscan_params != NULL) {
+ scan_params = wpa_s->autoscan_params;
+ goto scan;
+ }
+
/* Find the starting point from which to continue scanning */
ssid = wpa_s->conf->ssid;
if (wpa_s->prev_sched_ssid) {
@@ -808,7 +868,8 @@
if (!ssid || !wpa_s->prev_sched_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
- wpa_s->sched_scan_interval = 10;
+ if (wpa_s->sched_scan_interval == 0)
+ wpa_s->sched_scan_interval = 10;
wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
wpa_s->first_sched_scan = 1;
ssid = wpa_s->conf->ssid;
@@ -821,7 +882,7 @@
}
while (ssid) {
- if (ssid->disabled)
+ if (wpas_network_disabled(wpa_s, ssid))
goto next;
if (params.num_filter_ssids < wpa_s->max_match_sets &&
@@ -855,6 +916,11 @@
params.num_ssids++;
if (params.num_ssids >= max_sched_scan_ssids) {
wpa_s->prev_sched_ssid = ssid;
+ do {
+ ssid = ssid->next;
+ } while (ssid &&
+ (wpas_network_disabled(wpa_s, ssid) ||
+ !ssid->scan_ssid));
break;
}
}
@@ -872,17 +938,20 @@
if (wpa_s->wps)
wps_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms);
+ scan_params = ¶ms;
+
+scan:
if (ssid || !wpa_s->first_sched_scan) {
wpa_dbg(wpa_s, MSG_DEBUG,
- "Starting sched scan: interval %d (no timeout)",
- wpa_s->sched_scan_interval);
- } else {
- wpa_dbg(wpa_s, MSG_DEBUG,
"Starting sched scan: interval %d timeout %d",
wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout);
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Starting sched scan: interval %d (no timeout)",
+ wpa_s->sched_scan_interval);
}
- ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms,
+ ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
wpa_s->sched_scan_interval);
wpabuf_free(wps_ie);
os_free(params.filter_ssids);
@@ -1220,6 +1289,7 @@
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *r = scan_res->res[i];
+ u8 *pos;
if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID))
== WPA_SCAN_LEVEL_DBM) {
int snr = r->level - r->noise;
@@ -1234,11 +1304,62 @@
MAC2STR(r->bssid), r->freq, r->qual,
r->noise, r->level, r->flags);
}
+ pos = (u8 *) (r + 1);
+ if (r->ie_len)
+ wpa_hexdump(MSG_EXCESSIVE, "IEs", pos, r->ie_len);
+ pos += r->ie_len;
+ if (r->beacon_ie_len)
+ wpa_hexdump(MSG_EXCESSIVE, "Beacon IEs",
+ pos, r->beacon_ie_len);
}
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
+int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ size_t i;
+
+ if (wpa_s->bssid_filter == NULL)
+ return 1;
+
+ for (i = 0; i < wpa_s->bssid_filter_count; i++) {
+ if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid,
+ ETH_ALEN) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void filter_scan_res(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *res)
+{
+ size_t i, j;
+
+ if (wpa_s->bssid_filter == NULL)
+ return;
+
+ for (i = 0, j = 0; i < res->num; i++) {
+ if (wpa_supplicant_filter_bssid_match(wpa_s,
+ res->res[i]->bssid)) {
+ res->res[j++] = res->res[i];
+ } else {
+ os_free(res->res[i]);
+ res->res[i] = NULL;
+ }
+ }
+
+ if (res->num != j) {
+ wpa_printf(MSG_DEBUG, "Filtered out %d scan results",
+ (int) (res->num - j));
+ res->num = j;
+ }
+}
+
+
/**
* wpa_supplicant_get_scan_results - Get scan results
* @wpa_s: Pointer to wpa_supplicant data
@@ -1263,6 +1384,7 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
return NULL;
}
+ filter_scan_res(wpa_s, scan_res);
#ifdef CONFIG_WPS
if (wpas_wps_in_progress(wpa_s)) {
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index b794105..b0ddf97 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -9,7 +9,7 @@
#ifndef SCAN_H
#define SCAN_H
-int wpa_supplicant_enabled_networks(struct wpa_config *conf);
+int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s);
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
int sec, int usec);
@@ -32,5 +32,7 @@
u32 vendor_type);
struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
const struct wpa_scan_res *res, u32 vendor_type);
+int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
+ const u8 *bssid);
#endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 690f395..c7187e4 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -26,12 +26,14 @@
#include "bss.h"
#include "scan.h"
#include "sme.h"
+#include "hs20_supplicant.h"
#define SME_AUTH_TIMEOUT 5
#define SME_ASSOC_TIMEOUT 5
static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx);
static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
+static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
#ifdef CONFIG_IEEE80211W
static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
#endif /* CONFIG_IEEE80211W */
@@ -221,6 +223,21 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_HS20
+ if (wpa_s->conf->hs20) {
+ struct wpabuf *hs20;
+ hs20 = wpabuf_alloc(20);
+ if (hs20) {
+ wpas_hs20_add_indication(hs20);
+ os_memcpy(wpa_s->sme.assoc_req_ie +
+ wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(hs20), wpabuf_len(hs20));
+ wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20);
+ wpabuf_free(hs20);
+ }
+ }
+#endif /* CONFIG_HS20 */
+
#ifdef CONFIG_INTERWORKING
if (wpa_s->conf->interworking) {
u8 *pos = wpa_s->sme.assoc_req_ie;
@@ -315,6 +332,7 @@
wpa_s->sme.auth_alg == data->auth.auth_type ||
wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP) {
wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
return;
}
@@ -371,6 +389,8 @@
params.ssid = wpa_s->sme.ssid;
params.ssid_len = wpa_s->sme.ssid_len;
params.freq = wpa_s->sme.freq;
+ params.bg_scan_period = wpa_s->current_ssid ?
+ wpa_s->current_ssid->bg_scan_period : -1;
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;
@@ -429,6 +449,7 @@
wpa_msg(wpa_s, MSG_INFO, "SME: Association request to the "
"driver failed");
wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
return;
}
@@ -604,6 +625,263 @@
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+ eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
+}
+
+
+static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
+ const u8 *chan_list, u8 num_channels,
+ u8 num_intol)
+{
+ struct ieee80211_2040_bss_coex_ie *bc_ie;
+ struct ieee80211_2040_intol_chan_report *ic_report;
+ struct wpabuf *buf;
+
+ wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR,
+ MAC2STR(wpa_s->bssid));
+
+ buf = wpabuf_alloc(2 + /* action.category + action_code */
+ sizeof(struct ieee80211_2040_bss_coex_ie) +
+ sizeof(struct ieee80211_2040_intol_chan_report) +
+ num_channels);
+ if (buf == NULL)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+ wpabuf_put_u8(buf, WLAN_PA_20_40_BSS_COEX);
+
+ bc_ie = wpabuf_put(buf, sizeof(*bc_ie));
+ bc_ie->element_id = WLAN_EID_20_40_BSS_COEXISTENCE;
+ bc_ie->length = 1;
+ if (num_intol)
+ bc_ie->coex_param |= WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ;
+
+ if (num_channels > 0) {
+ ic_report = wpabuf_put(buf, sizeof(*ic_report));
+ ic_report->element_id = WLAN_EID_20_40_BSS_INTOLERANT;
+ ic_report->length = num_channels + 1;
+ ic_report->op_class = 0;
+ os_memcpy(wpabuf_put(buf, num_channels), chan_list,
+ num_channels);
+ }
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "SME: Failed to send 20/40 BSS Coexistence frame");
+ }
+
+ wpabuf_free(buf);
+}
+
+
+/**
+ * enum wpas_band - Frequency band
+ * @WPAS_BAND_2GHZ: 2.4 GHz ISM band
+ * @WPAS_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
+ */
+enum wpas_band {
+ WPAS_BAND_2GHZ,
+ WPAS_BAND_5GHZ,
+ WPAS_BAND_INVALID
+};
+
+/**
+ * freq_to_channel - Convert frequency into channel info
+ * @channel: Buffer for returning channel number
+ * Returns: Band (2 or 5 GHz)
+ */
+static enum wpas_band freq_to_channel(int freq, u8 *channel)
+{
+ enum wpas_band band = (freq <= 2484) ? WPAS_BAND_2GHZ : WPAS_BAND_5GHZ;
+ u8 chan = 0;
+
+ if (freq >= 2412 && freq <= 2472)
+ chan = (freq - 2407) / 5;
+ else if (freq == 2484)
+ chan = 14;
+ else if (freq >= 5180 && freq <= 5805)
+ chan = (freq - 5000) / 5;
+
+ *channel = chan;
+ return band;
+}
+
+
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss;
+ const u8 *ie;
+ u16 ht_cap;
+ u8 chan_list[P2P_MAX_CHANNELS], channel;
+ u8 num_channels = 0, num_intol = 0, i;
+
+ if (!wpa_s->sme.sched_obss_scan)
+ return 0;
+
+ wpa_s->sme.sched_obss_scan = 0;
+ if (!wpa_s->current_bss || wpa_s->wpa_state != WPA_COMPLETED)
+ return 1;
+
+ /*
+ * Check whether AP uses regulatory triplet or channel triplet in
+ * country info. Right now the operating class of the BSS channel
+ * width trigger event is "unknown" (IEEE Std 802.11-2012 10.15.12),
+ * based on the assumption that operating class triplet is not used in
+ * beacon frame. If the First Channel Number/Operating Extension
+ * Identifier octet has a positive integer value of 201 or greater,
+ * then its operating class triplet.
+ *
+ * TODO: If Supported Operating Classes element is present in beacon
+ * frame, have to lookup operating class in Annex E and fill them in
+ * 2040 coex frame.
+ */
+ ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
+ if (ie && (ie[1] >= 6) && (ie[5] >= 201))
+ return 1;
+
+ os_memset(chan_list, 0, sizeof(chan_list));
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ /* Skip other band bss */
+ if (freq_to_channel(bss->freq, &channel) != WPAS_BAND_2GHZ)
+ continue;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
+ ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
+
+ if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
+ /* Check whether the channel is already considered */
+ for (i = 0; i < num_channels; i++) {
+ if (channel == chan_list[i])
+ break;
+ }
+ if (i != num_channels)
+ continue;
+
+ if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
+ num_intol++;
+
+ chan_list[num_channels++] = channel;
+ }
+ }
+
+ sme_send_2040_bss_coex(wpa_s, chan_list, num_channels, num_intol);
+ return 1;
+}
+
+
+static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+ u16 num_modes,
+ enum hostapd_hw_mode mode)
+{
+ u16 i;
+
+ for (i = 0; i < num_modes; i++) {
+ if (modes[i].mode == mode)
+ return &modes[i];
+ }
+
+ return NULL;
+}
+
+
+static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode band,
+ struct wpa_driver_scan_params *params)
+{
+ /* Include only supported channels for the specified band */
+ struct hostapd_hw_modes *mode;
+ int count, i;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ if (mode == NULL) {
+ /* No channels supported in this band - use empty list */
+ params->freqs = os_zalloc(sizeof(int));
+ return;
+ }
+
+ params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+ if (params->freqs == NULL)
+ return;
+ for (count = 0, i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ params->freqs[count++] = mode->channels[i].freq;
+ }
+}
+
+
+static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct wpa_driver_scan_params params;
+
+ if (!wpa_s->current_bss) {
+ wpa_printf(MSG_DEBUG, "SME OBSS: Ignore scan request");
+ return;
+ }
+
+ os_memset(¶ms, 0, sizeof(params));
+ wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, ¶ms);
+ wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
+
+ if (wpa_supplicant_trigger_scan(wpa_s, ¶ms))
+ wpa_printf(MSG_DEBUG, "SME OBSS: Failed to trigger scan");
+ else
+ wpa_s->sme.sched_obss_scan = 1;
+ os_free(params.freqs);
+
+ eloop_register_timeout(wpa_s->sme.obss_scan_int, 0,
+ sme_obss_scan_timeout, wpa_s, NULL);
+}
+
+
+void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
+{
+ const u8 *ie;
+ struct wpa_bss *bss = wpa_s->current_bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
+ wpa_s->sme.sched_obss_scan = 0;
+ if (!enable)
+ return;
+
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) || ssid == NULL ||
+ ssid->mode != IEEE80211_MODE_INFRA)
+ return; /* Not using station SME in wpa_supplicant */
+
+ if (!wpa_s->hw.modes ||
+ !(wpa_s->hw.modes->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ return; /* Driver does not support HT40 */
+
+ if (bss == NULL || bss->freq < 2400 || bss->freq > 2500)
+ return; /* Not associated on 2.4 GHz band */
+
+ /* Check whether AP supports HT40 */
+ ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_CAP);
+ if (!ie || ie[1] < 2 ||
+ !(WPA_GET_LE16(ie + 2) & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ return; /* AP does not support HT40 */
+
+ ie = wpa_bss_get_ie(wpa_s->current_bss,
+ WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS);
+ if (!ie || ie[1] < 14)
+ return; /* AP does not request OBSS scans */
+
+ wpa_s->sme.obss_scan_int = WPA_GET_LE16(ie + 6);
+ if (wpa_s->sme.obss_scan_int < 10) {
+ wpa_printf(MSG_DEBUG, "SME: Invalid OBSS Scan Interval %u "
+ "replaced with the minimum 10 sec",
+ wpa_s->sme.obss_scan_int);
+ wpa_s->sme.obss_scan_int = 10;
+ }
+ wpa_printf(MSG_DEBUG, "SME: OBSS Scan Interval %u sec",
+ wpa_s->sme.obss_scan_int);
+ eloop_register_timeout(wpa_s->sme.obss_scan_int, 0,
+ sme_obss_scan_timeout, wpa_s, NULL);
}
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index 33530bb..a7cc507 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -35,6 +35,9 @@
const u8 *prev_pending_bssid);
void sme_deinit(struct wpa_supplicant *wpa_s);
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
+void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
+
#else /* CONFIG_SME */
static inline void sme_authenticate(struct wpa_supplicant *wpa_s,
@@ -95,6 +98,16 @@
{
}
+static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline void sme_sched_obss_scan(struct wpa_supplicant *wpa_s,
+ int enable)
+{
+}
+
#endif /* CONFIG_SME */
#endif /* SME_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 8abf2ae..c631cd1 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, 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 "utils/edit.h"
#include "utils/list.h"
#include "common/version.h"
+#include "common/ieee802_11_defs.h"
#ifdef ANDROID
#include <cutils/properties.h>
#endif /* ANDROID */
@@ -873,6 +874,78 @@
#endif /* CONFIG_WPS_OOB */
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc >= 1)
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC %s",
+ argv[0]);
+ else
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC");
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long WPS_NFC command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid WPS_NFC_TOKEN command: need one argument:\n"
+ "format: WPS or NDEF\n");
+ return -1;
+ }
+ if (argc >= 1)
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s",
+ argv[0]);
+ else
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN");
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long WPS_NFC_TOKEN command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ int ret;
+ char *buf;
+ size_t buflen;
+
+ if (argc != 1) {
+ printf("Invalid 'wps_nfc_tag_read' command - one argument "
+ "is required.\n");
+ return -1;
+ }
+
+ buflen = 18 + os_strlen(argv[0]);
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return -1;
+ os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
+
+ ret = wpa_ctrl_command(ctrl, buf);
+ os_free(buf);
+
+ return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -1128,6 +1201,32 @@
}
+#ifdef CONFIG_WPS_NFC
+static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc != 2) {
+ printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two "
+ "arguments:\n"
+ "- WPS/NDEF: token format\n"
+ "- UUID: specify which AP to use\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_NFC_CONFIG_TOKEN %s %s",
+ argv[0], argv[1]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long WPS_ER_NFC_CONFIG_TOKEN command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_WPS_NFC */
+
+
static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -1490,7 +1589,12 @@
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
+ if (argc > 1)
+ res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s %s",
+ argv[0], argv[1]);
+ else
+ res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s",
+ argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
@@ -1623,6 +1727,61 @@
}
+static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "LIST_CREDS");
+}
+
+
+static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "ADD_CRED");
+}
+
+
+static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[32];
+ int res;
+
+ if (argc < 1) {
+ printf("Invalid REMOVE_CRED command: needs one argument "
+ "(cred id)\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "REMOVE_CRED %s", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd))
+ return -1;
+ cmd[sizeof(cmd) - 1] = '\0';
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc != 3) {
+ printf("Invalid SET_CRED command: needs three arguments\n"
+ "(cred id, variable name, and value)\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "SET_CRED %s %s %s",
+ argv[0], argv[1], argv[2]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long SET_CRED command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1668,8 +1827,9 @@
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "BSS %s\t%s\t%s", argv[0],
- argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "");
+ res = os_snprintf(cmd, sizeof(cmd), "BSS %s%s%s%s%s", argv[0],
+ argc > 1 ? " " : "", argc > 1 ? argv[1] : "",
+ argc > 2 ? " " : "", argc > 2 ? argv[2] : "");
if (res < 0 || (size_t) res >= sizeof(cmd))
return -1;
@@ -1848,7 +2008,7 @@
return -1;
}
len = sizeof(buf) - 1;
- ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
wpa_cli_msg_cb);
if (ret == -2) {
printf("'%s' command timed out.\n", cmd);
@@ -1859,7 +2019,7 @@
}
buf[len] = '\0';
- if (memcmp(buf, "FAIL", 4) == 0)
+ if (os_memcmp(buf, "FAIL", 4) == 0)
return -1;
printf("%s", buf);
@@ -1884,6 +2044,42 @@
return -1;
}
+
+
+static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+ if (argc < 1) {
+ printf("Invalid 'deauthenticate' command - exactly one "
+ "argument, STA address, is required.\n");
+ return -1;
+ }
+ if (argc > 1)
+ os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
+ argv[0], argv[1]);
+ else
+ os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+ if (argc < 1) {
+ printf("Invalid 'disassociate' command - exactly one "
+ "argument, STA address, is required.\n");
+ return -1;
+ }
+ if (argc > 1)
+ os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
+ argv[0], argv[1]);
+ else
+ os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
+ return wpa_ctrl_command(ctrl, buf);
+}
#endif /* CONFIG_AP */
@@ -1968,7 +2164,14 @@
"arguments (address and pbc/PIN)\n");
return -1;
}
-
+#ifdef ANDROID_P2P
+ if (argc > 5)
+ res = os_snprintf(cmd, sizeof(cmd),
+ "P2P_CONNECT %s %s %s %s %s %s",
+ argv[0], argv[1], argv[2], argv[3],
+ argv[4], argv[5]);
+ else
+#endif
if (argc > 4)
res = os_snprintf(cmd, sizeof(cmd),
"P2P_CONNECT %s %s %s %s %s",
@@ -2357,7 +2560,7 @@
if (ctrl_conn == NULL)
return -1;
len = sizeof(buf) - 1;
- ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
wpa_cli_msg_cb);
if (ret == -2) {
printf("'%s' command timed out.\n", cmd);
@@ -2368,7 +2571,7 @@
}
buf[len] = '\0';
- if (memcmp(buf, "FAIL", 4) == 0)
+ if (os_memcmp(buf, "FAIL", 4) == 0)
return -1;
pos = buf;
@@ -2588,6 +2791,60 @@
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+
+static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[100];
+ int res;
+
+ if (argc != 2) {
+ printf("Invalid HS20_ANQP_GET command: needs two arguments "
+ "(addr and subtype list)\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "HS20_ANQP_GET %s %s",
+ argv[0], argv[1]);
+ if (res < 0 || (size_t) res >= sizeof(cmd))
+ return -1;
+ cmd[sizeof(cmd) - 1] = '\0';
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[512];
+ int res;
+
+ if (argc == 0) {
+ printf("Command needs one or two arguments (dst mac addr and "
+ "optional home realm)\n");
+ return -1;
+ }
+
+ if (argc == 1)
+ res = os_snprintf(cmd, sizeof(cmd),
+ "HS20_GET_NAI_HOME_REALM_LIST %s",
+ argv[0]);
+ else
+ res = os_snprintf(cmd, sizeof(cmd),
+ "HS20_GET_NAI_HOME_REALM_LIST %s %s",
+ argv[0], argv[1]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long command.\n");
+ return -1;
+ }
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+#endif /* CONFIG_HS20 */
+
+
static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2684,6 +2941,29 @@
return wpa_ctrl_command(ctrl, "REAUTHENTICATE");
}
+
+#ifdef CONFIG_AUTOSCAN
+
+static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc == 0)
+ return wpa_ctrl_command(ctrl, "AUTOSCAN ");
+
+ res = os_snprintf(cmd, sizeof(cmd), "AUTOSCAN %s", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long AUTOSCAN command.\n");
+ return -1;
+ }
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+
#ifdef ANDROID
static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
@@ -2827,6 +3107,18 @@
{ "get_network", wpa_cli_cmd_get_network,
cli_cmd_flag_none,
"<network id> <variable> = get network variables" },
+ { "list_creds", wpa_cli_cmd_list_creds,
+ cli_cmd_flag_none,
+ "= list configured credentials" },
+ { "add_cred", wpa_cli_cmd_add_cred,
+ cli_cmd_flag_none,
+ "= add a credential" },
+ { "remove_cred", wpa_cli_cmd_remove_cred,
+ cli_cmd_flag_none,
+ "<cred id> = remove a credential" },
+ { "set_cred", wpa_cli_cmd_set_cred,
+ cli_cmd_flag_sensitive,
+ "<cred id> <variable> <value> = set credential variables" },
{ "save_config", wpa_cli_cmd_save_config,
cli_cmd_flag_none,
"= save the current configuration" },
@@ -2903,6 +3195,17 @@
cli_cmd_flag_sensitive,
"<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
#endif /* CONFIG_WPS_OOB */
+#ifdef CONFIG_WPS_NFC
+ { "wps_nfc", wpa_cli_cmd_wps_nfc,
+ cli_cmd_flag_none,
+ "[BSSID] = start Wi-Fi Protected Setup: NFC" },
+ { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token,
+ cli_cmd_flag_none,
+ "<WPS|NDEF> = create password token" },
+ { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read,
+ cli_cmd_flag_sensitive,
+ "<hexdump of payload> = report read NFC tag with WPS data" },
+#endif /* CONFIG_WPS_NFC */
{ "wps_reg", wpa_cli_cmd_wps_reg,
cli_cmd_flag_sensitive,
"<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
@@ -2930,6 +3233,11 @@
{ "wps_er_config", wpa_cli_cmd_wps_er_config,
cli_cmd_flag_sensitive,
"<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
+#ifdef CONFIG_WPS_NFC
+ { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token,
+ cli_cmd_flag_none,
+ "<WPS/NDEF> <UUID> = build NFC configuration token" },
+#endif /* CONFIG_WPS_NFC */
{ "ibss_rsn", wpa_cli_cmd_ibss_rsn,
cli_cmd_flag_none,
"<addr> = request RSN authentication with <addr> in IBSS" },
@@ -2940,6 +3248,12 @@
{ "all_sta", wpa_cli_cmd_all_sta,
cli_cmd_flag_none,
"= get information about all associated stations (AP)" },
+ { "deauthenticate", wpa_cli_cmd_deauthenticate,
+ cli_cmd_flag_none,
+ "<addr> = deauthenticate a station" },
+ { "disassociate", wpa_cli_cmd_disassociate,
+ cli_cmd_flag_none,
+ "<addr> = disassociate a station" },
#endif /* CONFIG_AP */
{ "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
"= notification of suspend/hibernate" },
@@ -3034,6 +3348,14 @@
{ "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
"<addr> <info id>[,<info id>]... = request ANQP information" },
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, cli_cmd_flag_none,
+ "<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information"
+ },
+ { "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
+ cli_cmd_flag_none,
+ "<addr> <home realm> = get HS20 nai home realm list" },
+#endif /* CONFIG_HS20 */
{ "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
"<0/1> = disable/enable automatic reconnection" },
{ "tdls_discover", wpa_cli_cmd_tdls_discover,
@@ -3050,6 +3372,10 @@
"= get signal parameters" },
{ "reauthenticate", wpa_cli_cmd_reauthenticate, cli_cmd_flag_none,
"= trigger IEEE 802.1X/EAPOL reauthentication" },
+#ifdef CONFIG_AUTOSCAN
+ { "autoscan", wpa_cli_cmd_autoscan, cli_cmd_flag_none,
+ "[params] = Set or unset (if none) autoscan parameters" },
+#endif /* CONFIG_AUTOSCAN */
#ifdef ANDROID
{ "driver", wpa_cli_cmd_driver,
cli_cmd_flag_none,
@@ -3758,8 +4084,9 @@
ctrl_conn = wpa_ctrl_open(global);
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
if (ctrl_conn == NULL) {
- perror("Failed to connect to wpa_supplicant - "
- "wpa_ctrl_open");
+ fprintf(stderr, "Failed to connect to wpa_supplicant "
+ "global interface: %s error: %s\n",
+ global, strerror(errno));
return -1;
}
}
@@ -3781,8 +4108,8 @@
}
if (!warning_displayed) {
- printf("Could not connect to wpa_supplicant - "
- "re-trying\n");
+ printf("Could not connect to wpa_supplicant: "
+ "%s - re-trying\n", ctrl_ifname);
warning_displayed = 1;
}
os_sleep(1, 0);
@@ -3791,8 +4118,9 @@
} else {
if (!global &&
wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
- perror("Failed to connect to wpa_supplicant - "
- "wpa_ctrl_open");
+ fprintf(stderr, "Failed to connect to non-global "
+ "ctrl_ifname: %s error: %s\n",
+ ctrl_ifname, strerror(errno));
return -1;
}
diff --git a/wpa_supplicant/wpa_gui-qt4/signalbar.cpp b/wpa_supplicant/wpa_gui-qt4/signalbar.cpp
index f2688d5..2bba582 100644
--- a/wpa_supplicant/wpa_gui-qt4/signalbar.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/signalbar.cpp
@@ -2,14 +2,8 @@
* wpa_gui - SignalBar class
* Copyright (c) 2011, Kel Modderman <kel@otaku42.de>
*
- * 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 <cstdio>
diff --git a/wpa_supplicant/wpa_gui-qt4/signalbar.h b/wpa_supplicant/wpa_gui-qt4/signalbar.h
index 3d5dec1..37da5dd 100644
--- a/wpa_supplicant/wpa_gui-qt4/signalbar.h
+++ b/wpa_supplicant/wpa_gui-qt4/signalbar.h
@@ -2,14 +2,8 @@
* wpa_gui - SignalBar class
* Copyright (c) 2011, Kel Modderman <kel@otaku42.de>
*
- * 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 SIGNALBAR_H
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
index 97211e4..42e14f0 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -6,16 +6,12 @@
* See README for more details.
*/
-#ifdef __MINGW32__
-/* Need to get getopt() */
-#include <unistd.h>
-#endif
-
#ifdef CONFIG_NATIVE_WINDOWS
#include <windows.h>
#endif /* CONFIG_NATIVE_WINDOWS */
#include <cstdio>
+#include <unistd.h>
#include <QMessageBox>
#include <QCloseEvent>
#include <QImageReader>
@@ -713,17 +709,13 @@
void WpaGui::helpAbout()
{
QMessageBox::about(this, "wpa_gui for wpa_supplicant",
- "Copyright (c) 2003-2011,\n"
+ "Copyright (c) 2003-2012,\n"
"Jouni Malinen <j@w1.fi>\n"
"and contributors.\n"
"\n"
- "This program is free software. You can\n"
- "distribute it and/or modify it under the terms "
- "of\n"
- "the GNU General Public License version 2.\n"
- "\n"
- "Alternatively, this software may be distributed\n"
- "under the terms of the BSD license.\n"
+ "This software may be distributed under\n"
+ "the terms of the BSD license.\n"
+ "See README for more details.\n"
"\n"
"This product includes software developed\n"
"by the OpenSSL Project for use in the\n"
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 74476e2..ad6a080 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -643,7 +643,7 @@
}
if (bind(iface->fd, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ perror("wpa-priv-iface-init: bind(PF_UNIX)");
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index e1ad4d9..47abd9a 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -42,9 +42,11 @@
#include "p2p_supplicant.h"
#include "notify.h"
#include "bgscan.h"
+#include "autoscan.h"
#include "bss.h"
#include "scan.h"
#include "offchannel.h"
+#include "hs20_supplicant.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
@@ -348,7 +350,7 @@
}
-static void free_hw_features(struct wpa_supplicant *wpa_s)
+void free_hw_features(struct wpa_supplicant *wpa_s)
{
int i;
if (wpa_s->hw.modes == NULL)
@@ -367,6 +369,7 @@
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
bgscan_deinit(wpa_s);
+ autoscan_deinit(wpa_s);
scard_deinit(wpa_s->scard);
wpa_s->scard = NULL;
wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
@@ -445,6 +448,11 @@
wpa_s->gas = NULL;
free_hw_features(wpa_s);
+
+ os_free(wpa_s->bssid_filter);
+ wpa_s->bssid_filter = NULL;
+
+ wnm_bss_keep_alive_deinit(wpa_s);
}
@@ -564,6 +572,29 @@
#endif /* CONFIG_BGSCAN */
+static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
+{
+ if (autoscan_init(wpa_s, 0))
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
+}
+
+
+static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
+{
+ autoscan_deinit(wpa_s);
+}
+
+
+void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+ wpa_s->wpa_state == WPA_SCANNING) {
+ autoscan_deinit(wpa_s);
+ wpa_supplicant_start_autoscan(wpa_s);
+ }
+}
+
+
/**
* wpa_supplicant_set_state - Set current connection state
* @wpa_s: Pointer to wpa_supplicant data
@@ -610,6 +641,8 @@
#ifdef CONFIG_P2P
wpas_p2p_completed(wpa_s);
#endif /* CONFIG_P2P */
+
+ sme_sched_obss_scan(wpa_s, 1);
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
@@ -617,6 +650,7 @@
#ifndef IEEE8021X_EAPOL
wpa_drv_set_supp_port(wpa_s, 0);
#endif /* IEEE8021X_EAPOL */
+ sme_sched_obss_scan(wpa_s, 0);
}
wpa_s->wpa_state = state;
@@ -627,6 +661,12 @@
wpa_supplicant_stop_bgscan(wpa_s);
#endif /* CONFIG_BGSCAN */
+ if (state == WPA_AUTHENTICATING)
+ wpa_supplicant_stop_autoscan(wpa_s);
+
+ if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+ wpa_supplicant_start_autoscan(wpa_s);
+
if (wpa_s->wpa_state != old_state) {
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
@@ -670,7 +710,7 @@
wpa_s->mgmt_group_cipher = 0;
wpa_s->key_mgmt = 0;
if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
- wpa_s->wpa_state = WPA_DISCONNECTED;
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
if (wpa_s->wpa_state != old_state)
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
@@ -749,7 +789,7 @@
wpa_supplicant_update_config(wpa_s);
wpa_supplicant_clear_status(wpa_s);
- if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+ if (wpa_supplicant_enabled_networks(wpa_s)) {
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -1254,11 +1294,10 @@
u8 *pos;
size_t len;
int res;
- int p2p_group;
- p2p_group = wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE;
pos = wpa_ie + wpa_ie_len;
len = sizeof(wpa_ie) - wpa_ie_len;
- res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len, p2p_group);
+ res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
+ ssid->p2p_group);
if (res >= 0)
wpa_ie_len += res;
}
@@ -1279,6 +1318,20 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_HS20
+ if (wpa_s->conf->hs20) {
+ struct wpabuf *hs20;
+ hs20 = wpabuf_alloc(20);
+ if (hs20) {
+ wpas_hs20_add_indication(hs20);
+ os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20),
+ wpabuf_len(hs20));
+ wpa_ie_len += wpabuf_len(hs20);
+ wpabuf_free(hs20);
+ }
+ }
+#endif /* CONFIG_HS20 */
+
#ifdef CONFIG_INTERWORKING
if (wpa_s->conf->interworking) {
u8 *pos = wpa_ie;
@@ -1336,7 +1389,12 @@
if (bss) {
params.ssid = bss->ssid;
params.ssid_len = bss->ssid_len;
- if (!wpas_driver_bss_selection(wpa_s)) {
+ if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
+ wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
+ MACSTR " freq=%u MHz based on scan results "
+ "(bssid_set=%d)",
+ MAC2STR(bss->bssid), bss->freq,
+ ssid->bssid_set);
params.bssid = bss->bssid;
params.freq = bss->freq;
}
@@ -1362,6 +1420,7 @@
params.wpa_proto = wpa_s->wpa_proto;
params.auth_alg = algs;
params.mode = ssid->mode;
+ params.bg_scan_period = ssid->bg_scan_period;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i])
params.wep_key[i] = ssid->wep_key[i];
@@ -1441,6 +1500,7 @@
* succeed.
*/
wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
return;
}
@@ -1534,10 +1594,15 @@
int reason_code)
{
u8 *addr = NULL;
+ union wpa_event_data event;
if (!is_zero_ether_addr(wpa_s->bssid)) {
wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
addr = wpa_s->bssid;
+ os_memset(&event, 0, sizeof(event));
+ event.disassoc_info.reason_code = (u16) reason_code;
+ event.disassoc_info.locally_generated = 1;
+ wpa_supplicant_event(wpa_s, EVENT_DISASSOC, &event);
}
wpa_supplicant_clear_connection(wpa_s, addr);
@@ -1556,10 +1621,15 @@
int reason_code)
{
u8 *addr = NULL;
+ union wpa_event_data event;
if (!is_zero_ether_addr(wpa_s->bssid)) {
wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
addr = wpa_s->bssid;
+ os_memset(&event, 0, sizeof(event));
+ event.deauth_info.reason_code = (u16) reason_code;
+ event.deauth_info.locally_generated = 1;
+ wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
}
wpa_supplicant_clear_connection(wpa_s, addr);
@@ -1799,6 +1869,29 @@
/**
+ * wpa_supplicant_set_scan_interval - Set scan interval
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @scan_interval: scan interval in seconds
+ * Returns: 0 if succeed or -1 if scan_interval has an invalid value
+ *
+ */
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+ int scan_interval)
+{
+ if (scan_interval < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d",
+ scan_interval);
+ return -1;
+ }
+ wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
+ scan_interval);
+ wpa_s->scan_interval = scan_interval;
+
+ return 0;
+}
+
+
+/**
* wpa_supplicant_set_debug_params - Set global debug params
* @global: wpa_global structure
* @debug_level: debug level
@@ -1873,14 +1966,14 @@
entry = wpa_s->conf->ssid;
while (entry) {
- if (!entry->disabled &&
+ if (!wpas_network_disabled(wpa_s, entry) &&
((ssid_len == entry->ssid_len &&
os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
(!entry->bssid_set ||
os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
return entry;
#ifdef CONFIG_WPS
- if (!entry->disabled &&
+ if (!wpas_network_disabled(wpa_s, entry) &&
(entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
(entry->ssid == NULL || entry->ssid_len == 0) &&
(!entry->bssid_set ||
@@ -1888,7 +1981,7 @@
return entry;
#endif /* CONFIG_WPS */
- if (!entry->disabled && entry->bssid_set &&
+ if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
entry->ssid_len == 0 &&
os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
return entry;
@@ -2111,6 +2204,31 @@
}
+static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ const struct l2_ethhdr *eth;
+
+ if (len < sizeof(*eth))
+ return;
+ eth = (const struct l2_ethhdr *) buf;
+
+ if (os_memcmp(eth->h_dest, wpa_s->own_addr, ETH_ALEN) != 0 &&
+ !(eth->h_dest[0] & 0x01)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+ " (bridge - not for this interface - ignore)",
+ MAC2STR(src_addr), MAC2STR(eth->h_dest));
+ return;
+ }
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+ " (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
+ wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
+ len - sizeof(*eth));
+}
+
+
/**
* wpa_supplicant_driver_init - Initialize driver interface parameters
* @wpa_s: Pointer to wpa_supplicant data
@@ -2133,8 +2251,8 @@
wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
wpa_s->own_addr,
ETH_P_EAPOL,
- wpa_supplicant_rx_eapol, wpa_s,
- 0);
+ wpa_supplicant_rx_eapol_bridge,
+ wpa_s, 1);
if (wpa_s->l2_br == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
"connection for the bridge interface '%s'",
@@ -2155,7 +2273,7 @@
wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
wpa_s->prev_scan_wildcard = 0;
- if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+ if (wpa_supplicant_enabled_networks(wpa_s)) {
if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
100000))
wpa_supplicant_req_scan(wpa_s, interface_count,
@@ -2369,6 +2487,48 @@
#endif /* CONFIG_HT_OVERRIDES */
+static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
+{
+#ifdef PCSC_FUNCS
+ size_t len;
+
+ if (!wpa_s->conf->pcsc_reader)
+ return 0;
+
+ wpa_s->scard = scard_init(SCARD_TRY_BOTH, wpa_s->conf->pcsc_reader);
+ if (!wpa_s->scard)
+ return 1;
+
+ if (wpa_s->conf->pcsc_pin &&
+ scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) {
+ scard_deinit(wpa_s->scard);
+ wpa_s->scard = NULL;
+ wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed");
+ return -1;
+ }
+
+ len = sizeof(wpa_s->imsi) - 1;
+ if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
+ scard_deinit(wpa_s->scard);
+ wpa_s->scard = NULL;
+ wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
+ return -1;
+ }
+ wpa_s->imsi[len] = '\0';
+
+ wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
+
+ wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
+ wpa_s->imsi, wpa_s->mnc_len);
+
+ wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
+ eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* PCSC_FUNCS */
+
+ return 0;
+}
+
+
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
@@ -2528,6 +2688,7 @@
if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
wpa_s->drv_capa_known = 1;
wpa_s->drv_flags = capa.flags;
+ wpa_s->drv_enc = capa.enc;
wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
wpa_s->max_scan_ssids = capa.max_scan_ssids;
wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
@@ -2590,6 +2751,9 @@
if (wpa_bss_init(wpa_s) < 0)
return -1;
+ if (pcsc_reader_init(wpa_s) < 0)
+ return -1;
+
return 0;
}
@@ -2607,6 +2771,14 @@
wpa_supplicant_cleanup(wpa_s);
+#ifdef CONFIG_P2P
+ if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
+ "the management interface is being removed");
+ wpas_p2p_deinit_global(wpa_s->global);
+ }
+#endif /* CONFIG_P2P */
+
if (wpa_s->drv_priv)
wpa_drv_deinit(wpa_s);
@@ -2693,6 +2865,7 @@
global->ifaces = wpa_s;
wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
return wpa_s;
}
@@ -2821,6 +2994,14 @@
wpa_debug_open_file(params->wpa_debug_file_path);
if (params->wpa_debug_syslog)
wpa_debug_open_syslog();
+ if (params->wpa_debug_tracing) {
+ ret = wpa_debug_open_linux_tracing();
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "Failed to enable trace logging");
+ return NULL;
+ }
+ }
ret = eap_register_methods();
if (ret) {
@@ -2978,9 +3159,12 @@
os_free(global->params.override_driver);
os_free(global->params.override_ctrl_interface);
+ os_free(global->p2p_disallow_freq);
+
os_free(global);
wpa_debug_close_syslog();
wpa_debug_close_file();
+ wpa_debug_close_linux_tracing();
}
@@ -3129,15 +3313,119 @@
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
}
-#ifdef ANDROID_P2P
+
+#if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW)
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const char *field,
+ const char *value)
+{
+#ifdef IEEE8021X_EAPOL
+ struct eap_peer_config *eap = &ssid->eap;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
+ (const u8 *) value, os_strlen(value));
+
+ switch (wpa_supplicant_ctrl_req_from_string(field)) {
+ case WPA_CTRL_REQ_EAP_IDENTITY:
+ os_free(eap->identity);
+ eap->identity = (u8 *) os_strdup(value);
+ eap->identity_len = os_strlen(value);
+ eap->pending_req_identity = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ break;
+ case WPA_CTRL_REQ_EAP_PASSWORD:
+ os_free(eap->password);
+ eap->password = (u8 *) os_strdup(value);
+ eap->password_len = os_strlen(value);
+ eap->pending_req_password = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ break;
+ case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+ os_free(eap->new_password);
+ eap->new_password = (u8 *) os_strdup(value);
+ eap->new_password_len = os_strlen(value);
+ eap->pending_req_new_password = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ break;
+ case WPA_CTRL_REQ_EAP_PIN:
+ os_free(eap->pin);
+ eap->pin = os_strdup(value);
+ eap->pending_req_pin = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ break;
+ case WPA_CTRL_REQ_EAP_OTP:
+ os_free(eap->otp);
+ eap->otp = (u8 *) os_strdup(value);
+ eap->otp_len = os_strlen(value);
+ os_free(eap->pending_req_otp);
+ eap->pending_req_otp = NULL;
+ eap->pending_req_otp_len = 0;
+ break;
+ case WPA_CTRL_REQ_EAP_PASSPHRASE:
+ os_free(eap->private_key_passwd);
+ eap->private_key_passwd = (u8 *) os_strdup(value);
+ eap->pending_req_passphrase = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
+ return -1;
+ }
+
+ return 0;
+#else /* IEEE8021X_EAPOL */
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
+ return -1;
+#endif /* IEEE8021X_EAPOL */
+}
+#endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW */
+
+
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ int i;
+ unsigned int drv_enc;
+
+ if (ssid == NULL)
+ return 1;
+
+ if (ssid->disabled)
+ return 1;
+
+ if (wpa_s && wpa_s->drv_capa_known)
+ drv_enc = wpa_s->drv_enc;
+ else
+ drv_enc = (unsigned int) -1;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ size_t len = ssid->wep_key_len[i];
+ if (len == 0)
+ continue;
+ if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40))
+ continue;
+ if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104))
+ continue;
+ if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128))
+ continue;
+ return 1; /* invalid WEP key */
+ }
+
+ return 0;
+}
+
+
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
{
if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
return 1;
if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA)
return 0;
-
- /* IF conc_priority is not set, return -1 */
return -1;
}
-#endif
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index d393015..3ebbcc2 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -214,6 +214,22 @@
# to external program(s)
#wps_cred_processing=0
+# Vendor attribute in WPS M1, e.g., Windows 7 Vertical Pairing
+# The vendor attribute contents to be added in M1 (hex string)
+#wps_vendor_ext_m1=000137100100020001
+
+# NFC password token for WPS
+# These parameters can be used to configure a fixed NFC password token for the
+# station. This can be generated, e.g., with nfc_pw_token. When these
+# parameters are used, the station is assumed to be deployed with a NFC tag
+# that includes the matching NFC password token (e.g., written based on the
+# NDEF record from nfc_pw_token).
+#
+#wps_nfc_dev_pw_id: Device Password ID (16..65535)
+#wps_nfc_dh_pubkey: Hexdump of DH Public Key
+#wps_nfc_dh_privkey: Hexdump of DH Private Key
+#wps_nfc_dev_pw: Hexdump of Device Password
+
# Maximum number of BSS entries to keep in memory
# Default: 200
# This can be used to limit memory use on the BSS entries (cached scan
@@ -221,6 +237,18 @@
# of APs when using ap_scan=1 mode.
#bss_max_count=200
+# Automatic scan
+# This is an optional set of parameters for automatic scanning
+# within an interface in following format:
+#autoscan=<autoscan module name>:<module parameters>
+# autoscan is like bgscan but on disconnected or inactive state.
+# For instance, on exponential module parameters would be <base>:<limit>
+#autoscan=exponential:3:300
+# Which means a delay between scans on a base exponential of 3,
+# up to the limit of 300 seconds (3, 9, 27 ... 300)
+# For periodic module, parameters would be <fixed interval>
+#autoscan=periodic:30
+# So a delay of 30 seconds will be applied between each scan
# filter_ssids - SSID-based scan result filtering
# 0 = do not filter scan results (default)
@@ -239,23 +267,92 @@
# is enabled.
# hessid=00:11:22:33:44:55
-# Home Realm for Interworking
-#home_realm=example.com
+# credential block
+#
+# Each credential used for automatic network selection is configured as a set
+# of parameters that are compared to the information advertised by the APs when
+# interworking_select and interworking_connect commands are used.
+#
+# credential fields:
+#
+# 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
+# (and similarly in struct wpa_ssid for network blocks) to change the
+# Interworking automatic networking selection behavior. The matching
+# network (based on either an enabled network block or a credential)
+# with the highest priority value will be selected.
+#
+# pcsc: Use PC/SC and SIM/USIM card
+#
+# realm: Home Realm for Interworking
+#
+# username: Username for Interworking network selection
+#
+# password: Password for Interworking network selection
+#
+# ca_cert: CA certificate for Interworking network selection
+#
+# client_cert: File path to client certificate file (PEM/DER)
+# This field is used with Interworking networking selection for a case
+# where client certificate/private key is used for authentication
+# (EAP-TLS). Full path to the file should be used since working
+# directory may change when wpa_supplicant is run in the background.
+#
+# Alternatively, a named configuration blob can be used by setting
+# this to blob://blob_name.
+#
+# private_key: File path to client private key file (PEM/DER/PFX)
+# When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+# commented out. Both the private key and certificate will be read
+# from the PKCS#12 file in this case. Full path to the file should be
+# used since working directory may change when wpa_supplicant is run
+# in the background.
+#
+# Windows certificate store can be used by leaving client_cert out and
+# configuring private_key in one of the following formats:
+#
+# cert://substring_to_match
+#
+# hash://certificate_thumbprint_in_hex
+#
+# For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+#
+# Note that when running wpa_supplicant as an application, the user
+# certificate store (My user account) is used, whereas computer store
+# (Computer account) is used when running wpasvc as a service.
+#
+# Alternatively, a named configuration blob can be used by setting
+# this to blob://blob_name.
+#
+# private_key_passwd: Password for private key file
+#
+# imsi: IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+#
+# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
+# format
+#
+# domain: Home service provider FQDN
+# This is used to compare against the Domain Name List to figure out
+# whether the AP is operated by the Home SP.
+#
+# for example:
+#
+#cred={
+# realm="example.com"
+# username="user@example.com"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+#}
+#
+#cred={
+# imsi="310026-000000000"
+# milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82"
+#}
-# Username for Interworking network selection
-#home_username=user
-
-# Password for Interworking network selection
-#home_password=secret
-
-# CA certificate for Interworking network selection
-#home_ca_cert=/etc/cert/ca.pem
-
-# IMSI in <MCC> | <MNC> | '-' | <MSIN> format
-#home_imsi=232010000000000
-
-# Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN> format
-#home_milenage=90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123
+# Hotspot 2.0
+# hs20=1
# network block
#
@@ -341,6 +438,16 @@
# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
# If not set, this defaults to: WPA-PSK WPA-EAP
#
+# ieee80211w: whether management frame protection is enabled
+# 0 = disabled (default)
+# 1 = optional
+# 2 = required
+# The most common configuration options for this based on the PMF (protected
+# management frames) certification program are:
+# PMF enabled: ieee80211w=1 and key_mgmt=WPA-EAP WPA-EAP-SHA256
+# PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
+# (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used)
+#
# auth_alg: list of allowed IEEE 802.11 authentication algorithms
# OPEN = Open System authentication (required for WPA/WPA2)
# SHARED = Shared Key authentication (requires static WEP keys)
@@ -587,6 +694,26 @@
# number of authentication servers. Strict EAP conformance mode can be
# configured by disabling workarounds with eap_workaround=0.
+# Station inactivity limit
+#
+# If a station does not send anything in ap_max_inactivity seconds, an
+# empty data frame is sent to it in order to verify whether it is
+# still in range. If this frame is not ACKed, the station will be
+# disassociated and then deauthenticated. This feature is used to
+# clear station table of old entries when the STAs move out of the
+# range.
+#
+# The station can associate again with the AP if it is still in range;
+# this inactivity poll is just used as a nicer way of verifying
+# inactivity; i.e., client will not report broken connection because
+# disassociation frame is not sent immediately without first polling
+# the STA with a data frame.
+# default: 300 (i.e., 5 minutes)
+#ap_max_inactivity=300
+
+# DTIM period in Beacon intervals for AP mode (default: 2)
+#dtim_period=2
+
# Example blocks:
# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 21fe5cc..3f6669d 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -161,6 +161,11 @@
int wpa_debug_syslog;
/**
+ * wpa_debug_tracing - Enable log output through Linux tracing
+ */
+ int wpa_debug_tracing;
+
+ /**
* override_driver - Optional driver parameter override
*
* This parameter can be used to override the driver parameter in
@@ -199,6 +204,12 @@
char *service;
};
+struct wpa_freq_range {
+ unsigned int min;
+ unsigned int max;
+};
+
+
/**
* struct wpa_global - Internal, global data for all %wpa_supplicant interfaces
*
@@ -214,19 +225,20 @@
size_t drv_count;
struct os_time suspend_time;
struct p2p_data *p2p;
+ struct wpa_supplicant *p2p_init_wpa_s;
struct wpa_supplicant *p2p_group_formation;
u8 p2p_dev_addr[ETH_ALEN];
struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
int p2p_disabled;
-#ifdef ANDROID_P2P
+ int cross_connection;
+ struct wpa_freq_range *p2p_disallow_freq;
+ unsigned int num_p2p_disallow_freq;
enum wpa_conc_pref {
WPA_CONC_PREF_NOT_SET,
WPA_CONC_PREF_STA,
WPA_CONC_PREF_P2P
} conc_pref;
-#endif
- int cross_connection;
};
@@ -259,6 +271,9 @@
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
char *dbus_new_path;
char *dbus_groupobj_path;
+#ifdef CONFIG_AP
+ char *preq_notify_peer;
+#endif /* CONFIG_AP */
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
char bridge_ifname[16];
@@ -287,6 +302,9 @@
void *drv_priv; /* private data used by driver_ops */
void *global_drv_priv;
+ u8 *bssid_filter;
+ size_t bssid_filter_count;
+
/* previous scan was wildcard when interleaving between
* wildcard scans and specific SSID scan when max_ssids=1 */
int prev_scan_wildcard;
@@ -330,6 +348,10 @@
* previous association event */
struct scard_data *scard;
+#ifdef PCSC_FUNCS
+ char imsi[20];
+ int mnc_len;
+#endif /* PCSC_FUNCS */
unsigned char last_eapol_src[ETH_ALEN];
@@ -345,6 +367,7 @@
int normal_scans; /* normal scans run before sched_scan */
unsigned int drv_flags;
+ unsigned int drv_enc;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -403,6 +426,9 @@
* sa_query_count octets of pending
* SA Query transaction identifiers */
struct os_time sa_query_start;
+ u8 sched_obss_scan;
+ u16 obss_scan_int;
+ u16 bss_max_idle_period;
} sme;
#endif /* CONFIG_SME */
@@ -460,7 +486,12 @@
u8 pending_join_dev_addr[ETH_ALEN];
int pending_join_wps_method;
int p2p_join_scan_count;
+ int auto_pd_scan_retry;
int force_long_sd;
+ u16 pending_pd_config_methods;
+ enum {
+ NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN
+ } pending_pd_use;
/*
* Whether cross connection is disallowed by the AP to which this
@@ -488,18 +519,32 @@
P2P_GROUP_REMOVAL_REQUESTED,
P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
P2P_GROUP_REMOVAL_UNAVAILABLE,
+ P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
#ifdef ANDROID_P2P
P2P_GROUP_REMOVAL_FREQ_CONFLICT
#endif
} removal_reason;
unsigned int p2p_cb_on_scan_complete:1;
+ unsigned int p2p_auto_join:1;
+ unsigned int p2p_auto_pd:1;
+ unsigned int p2p_persistent_group:1;
+ unsigned int p2p_fallback_to_go_neg:1;
+ unsigned int p2p_pd_before_go_neg:1;
+ int p2p_persistent_id;
+ int p2p_go_intent;
+ int p2p_connect_freq;
+ struct os_time p2p_auto_started;
#endif /* CONFIG_P2P */
struct wpa_ssid *bgscan_ssid;
const struct bgscan_ops *bgscan;
void *bgscan_priv;
+ const struct autoscan_ops *autoscan;
+ struct wpa_driver_scan_params *autoscan_params;
+ void *autoscan_priv;
+
struct wpa_ssid *connect_without_scan;
int after_wps;
@@ -529,6 +574,9 @@
} hw;
int pno;
+
+ /* WLAN_REASON_* reason codes. Negative if locally generated. */
+ int disconnect_reason;
};
@@ -556,6 +604,7 @@
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
int sec, int usec);
+void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s);
void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
enum wpa_states state);
struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s);
@@ -578,9 +627,12 @@
unsigned int expire_age);
int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
unsigned int expire_count);
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+ int scan_interval);
int wpa_supplicant_set_debug_params(struct wpa_global *global,
int debug_level, int debug_timestamp,
int debug_show_keys);
+void free_hw_features(struct wpa_supplicant *wpa_s);
void wpa_show_license(void);
@@ -606,9 +658,23 @@
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
-#ifdef ANDROID_P2P
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
-#endif
+void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s);
+
+/**
+ * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @ssid: Pointer to the network block the reply is for
+ * @field: field the response is a reply for
+ * @value: value (ie, password, etc) for @field
+ * Returns: 0 on success, non-zero on error
+ *
+ * Helper function to handle replies to control interface requests.
+ */
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const char *field,
+ const char *value);
/* events.c */
void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
@@ -617,6 +683,7 @@
struct wpa_ssid *ssid);
void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
/* eap_register.c */
int eap_register_methods(void);
@@ -631,4 +698,6 @@
return ((ssid->disabled == 2) || ssid->p2p_persistent_group);
}
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 5b9dc9e..fb4fa22 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -720,6 +720,15 @@
wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert);
}
+
+
+static void wpa_supplicant_status_cb(void *ctx, const char *status,
+ const char *parameter)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpas_notify_eap_status(wpa_s, status, parameter);
+}
#endif /* IEEE8021X_EAPOL */
@@ -751,6 +760,7 @@
ctx->port_cb = wpa_supplicant_port_cb;
ctx->cb = wpa_supplicant_eapol_cb;
ctx->cert_cb = wpa_supplicant_cert_cb;
+ ctx->status_cb = wpa_supplicant_status_cb;
ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 4965439..7356d1a 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "common.h"
#include "eloop.h"
#include "uuid.h"
+#include "crypto/random.h"
#include "crypto/dh_group5.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -20,6 +21,7 @@
#include "eap_peer/eap.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
+#include "wps/wps_attr_parse.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -263,6 +265,7 @@
ssid->eap.eap_methods = NULL;
if (!ssid->p2p_group)
ssid->temporary = 0;
+ ssid->bssid_set = 0;
} else {
wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
"received credential");
@@ -919,7 +922,8 @@
}
#endif /* CONFIG_AP */
- if (wpa_s->wpa_state == WPA_SCANNING) {
+ if (wpa_s->wpa_state == WPA_SCANNING ||
+ wpa_s->wpa_state == WPA_DISCONNECTED) {
wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan");
wpa_supplicant_cancel_scan(wpa_s);
wpas_clear_wps(wpa_s);
@@ -1113,8 +1117,10 @@
while (first && first->next)
first = first->next;
if (first && first != wpa_s) {
- os_memcpy(wps->uuid, wpa_s->global->ifaces->wps->uuid,
- WPS_UUID_LEN);
+ if (wps != wpa_s->global->ifaces->wps)
+ 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);
} else {
@@ -1130,6 +1136,23 @@
}
+static void wpas_wps_set_vendor_ext_m1(struct wpa_supplicant *wpa_s,
+ struct wps_context *wps)
+{
+ wpabuf_free(wps->dev.vendor_ext_m1);
+ wps->dev.vendor_ext_m1 = NULL;
+
+ if (wpa_s->conf->wps_vendor_ext_m1) {
+ wps->dev.vendor_ext_m1 =
+ wpabuf_dup(wpa_s->conf->wps_vendor_ext_m1);
+ if (!wps->dev.vendor_ext_m1) {
+ wpa_printf(MSG_ERROR, "WPS: Cannot "
+ "allocate memory for vendor_ext_m1");
+ }
+ }
+}
+
+
int wpas_wps_init(struct wpa_supplicant *wpa_s)
{
struct wps_context *wps;
@@ -1168,6 +1191,8 @@
os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types);
+ wpas_wps_set_vendor_ext_m1(wpa_s, wps);
+
wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
modes = wpa_s->hw.modes;
if (modes) {
@@ -1228,6 +1253,7 @@
wpabuf_free(wpa_s->wps->dh_privkey);
wpabuf_free(wpa_s->wps->oob_conf.pubkey_hash);
wpabuf_free(wpa_s->wps->oob_conf.dev_password);
+ wpabuf_free(wpa_s->wps->dev.vendor_ext_m1);
os_free(wpa_s->wps->network_key);
os_free(wpa_s->wps);
wpa_s->wps = NULL;
@@ -1648,6 +1674,34 @@
}
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef, const char *uuid)
+{
+ struct wpabuf *ret;
+ u8 u[UUID_LEN];
+
+ if (!wpa_s->wps_er)
+ return NULL;
+
+ if (uuid_str2bin(uuid, u))
+ return NULL;
+
+ ret = wps_er_nfc_config_token(wpa_s->wps_er, u);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
static int callbacks_pending = 0;
static void wpas_wps_terminate_cb(void *ctx)
@@ -1717,6 +1771,9 @@
wps->dev.num_sec_dev_types * WPS_DEV_TYPE_LEN);
}
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION)
+ wpas_wps_set_vendor_ext_m1(wpa_s, wps);
+
if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION)
wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
@@ -1733,3 +1790,132 @@
wps->dev.serial_number = wpa_s->conf->serial_number;
}
}
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
+{
+ return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id,
+ &wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey,
+ &wpa_s->conf->wps_nfc_dev_pw);
+}
+
+
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wps_context *wps = wpa_s->wps;
+ char pw[32 * 2 + 1];
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
+ wpa_s->conf->wps_nfc_dh_privkey == NULL ||
+ wpa_s->conf->wps_nfc_dev_pw == NULL)
+ return -1;
+
+ dh5_free(wps->dh_ctx);
+ wpabuf_free(wps->dh_pubkey);
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+ wps->dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+ if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
+ wps->dh_ctx = NULL;
+ wpabuf_free(wps->dh_pubkey);
+ wps->dh_pubkey = NULL;
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = NULL;
+ return -1;
+ }
+ wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
+ if (wps->dh_ctx == NULL)
+ return -1;
+
+ wpa_snprintf_hex_uppercase(pw, sizeof(pw),
+ wpabuf_head(wpa_s->conf->wps_nfc_dev_pw),
+ wpabuf_len(wpa_s->conf->wps_nfc_dev_pw));
+ return wpas_wps_start_pin(wpa_s, bssid, pw, 0,
+ wpa_s->conf->wps_nfc_dev_pw_id);
+}
+
+
+static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
+ struct wps_parse_attr *attr)
+{
+ if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
+ return -1;
+
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
+ "based on the received credential added");
+ wpa_s->normal_scans = 0;
+ wpa_supplicant_reinit_autoscan(wpa_s);
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return 0;
+}
+
+
+static int wpas_wps_add_nfc_password_token(struct wpa_supplicant *wpa_s,
+ struct wps_parse_attr *attr)
+{
+ return wps_registrar_add_nfc_password_token(
+ wpa_s->wps->registrar, attr->oob_dev_password,
+ attr->oob_dev_password_len);
+}
+
+
+static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *wps)
+{
+ struct wps_parse_attr attr;
+
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
+
+ if (wps_parse_msg(wps, &attr)) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
+ return -1;
+ }
+
+ if (attr.num_cred)
+ return wpas_wps_use_cred(wpa_s, &attr);
+
+#ifdef CONFIG_WPS_ER
+ if (attr.oob_dev_password)
+ return wpas_wps_add_nfc_password_token(wpa_s, &attr);
+#endif /* CONFIG_WPS_ER */
+
+ wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
+ return -1;
+}
+
+
+int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data)
+{
+ const struct wpabuf *wps = data;
+ struct wpabuf *tmp = NULL;
+ int ret;
+
+ if (wpabuf_len(data) < 4)
+ return -1;
+
+ if (*wpabuf_head_u8(data) != 0x10) {
+ /* Assume this contains full NDEF record */
+ tmp = ndef_parse_wifi(data);
+ if (tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
+ return -1;
+ }
+ wps = tmp;
+ }
+
+ ret = wpas_wps_nfc_tag_process(wpa_s, wps);
+ wpabuf_free(tmp);
+ return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index a5472a0..5a49a8f 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant / WPS integration
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -59,9 +59,15 @@
int id);
int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
const char *pin, struct wps_new_ap_settings *settings);
+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_token(struct wpa_supplicant *wpa_s, int ndef);
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data);
#else /* CONFIG_WPS */