Accumulative patch from commit b618a469c42120e984ab1c85ed6058504d1fca78
Author: Jouni Malinen <jouni@qca.qualcomm.com>
Date: Sat Feb 16 19:54:09 2013 +0200
Interworking: Select highest priority cred if multiple matches
Interworking: Select highest priority cred if multiple matches
GAS server: Fix a regression in GAS server callback
hostapd: Fix Max SP Length derivation from QoS Info
nl80211: Configure STA Capabilities and Extended Capabilities
Synchronize with wireless-testing.git include/uapi/linux/nl80211.h
WPS: Fix build without CONFIG_WPS_NFC
WPS: Add support for NFC handover select generation with wpa_supplicant
WPS: Update NFC connection handover documentation
WPS: Add support for config token generation with wpa_supplicant
WPS: Allow password token to be written with nfcpy
WPS: Use pre-configured NFC password token instead of overriding it
TDLS: Pass peer's Capability and Ext Capability info during sta_add
TDLS: Pass peer's HT Capability and QOS information during sta_add
nl80211: Add debug prints for STA add/set operations
TDLS: Fix add/set STA operation
Synchronize with wireless-testing.git include/uapi/linux/nl80211.h
WPS: Allow Device Password to be changed from M1 to M2
WPS: Fix wps_reg nfc-pw option
TDLS: Tear down peers when disconnecting from the AP
P2P: Do not use old scan result data for peer discovery
Use more accurate timestamps for scan results
P2P: Postpone P2P-DEVICE-FOUND if config_methods not known
P2P: Do not allow peer update to clear config_methods
WPS: Report NFC connection handover completion differently
P2P: Avoid concurrent scans during all steps of group formation
P2P: Cancel group formation timeout on group removal (on client)
WPS: Change listen time to match nfcpy default (250 ms)
WPS: Report only the carrier record from NFC to wpa_supplicant
WPS: Fetch only the carrier record from wpa_supplicant for NFC
WPS: Update nfcpy script to support AP mode NFC connection handover
WPS: Add command for fetching carrier record for NFC handover
WPS: Clean up debug prints with nfcpy
WPS: Remove 0.5 sec extra wait from NFC handover with nfcpy
WPS: Use alternating poll/listen for NFC peer discovery with nfcpy
WPS: Configure logging to show nfcpy log message
WPS: Add an example python script for NFC operations with hostapd
hostapd: Do not change HT40 capability due to OBSS scan
dbus: Add missing signal description for WPS (7)
EAP peer: Add Session-Id derivation to more EAP methods
EAP peer: Add Session-Id derivation
EAP-IKEV2 server: Fix invalid memory freeing operation
eap_proxy: Add a dummy implementation for compilation testing
eap_proxy: Add mechanism for allowing EAP methods to be offloaded
Android: Allow setgroups to be overridden from build configuration
P2P: Send p2p_stop_find event on failure to start pending p2p_find
P2P: Fix GO Probe Response IEs when Wi-Fi Display is enabled
Capability matching for 60 GHz band
nl80211: Add ctrl_iface message for AP mode connection rejection
P2P: Allow local configuration to use 5 GHz band 40 MHz channels
Fix BSS RANGE command for no exact id match cases
Change-Id: Iac9284bba31db40911aecc3adf2843c9b1576db1
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/README-WPS b/hostapd/README-WPS
index 87a6f91..654b5bc 100644
--- a/hostapd/README-WPS
+++ b/hostapd/README-WPS
@@ -338,3 +338,17 @@
internal Registrar. This allows station Enrollee from which the password
token was received to run through WPS protocol to provision the
credential.
+
+"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
+contents of a Handover Select Message for connection handover when this
+does not depend on the contents of the Handover Request Message. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
+<carrier from handover select>" is used to report completed NFC
+connection handover. The first parameter indicates whether the local
+device initiated or responded to the connection handover and the carrier
+records are the selected carrier from the handover request and select
+messages as a hexdump.
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 7b22dfd..e29ae2f 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2627,15 +2627,19 @@
"wps_nfc_dev_pw_id value", line);
errors++;
}
+ bss->wps_nfc_pw_from_config = 1;
} 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);
+ bss->wps_nfc_pw_from_config = 1;
} 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);
+ bss->wps_nfc_pw_from_config = 1;
} 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);
+ bss->wps_nfc_pw_from_config = 1;
#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P_MANAGER
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 93b740e..f20721b 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -352,6 +352,59 @@
return -1;
}
+
+
+static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ struct wpabuf *buf;
+ int res;
+ char *pos;
+ int ndef;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ if (os_strcmp(pos, "WPS-CR") == 0)
+ buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
+ else
+ buf = NULL;
+ 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_nfc_report_handover(struct hostapd_data *hapd,
+ char *cmd)
+{
+ /*
+ * Since NFC connection handover provided full WPS Credential, there is
+ * no need for additional operations within hostapd. Just report this in
+ * debug log.
+ */
+ wpa_printf(MSG_DEBUG, "NFC: Connection handover reported: %s", cmd);
+ return 0;
+}
+
#endif /* CONFIG_WPS_NFC */
@@ -913,6 +966,12 @@
} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
reply_len = hostapd_ctrl_iface_wps_nfc_token(
hapd, buf + 14, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+ reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
+ hapd, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
+ if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
+ reply_len = -1;
#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
#ifdef CONFIG_WNM
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index b693fa0..1537275 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -475,6 +475,29 @@
}
return wpa_ctrl_command(ctrl, cmd);
}
+
+
+static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char cmd[64];
+ int res;
+
+ if (argc != 2) {
+ printf("Invalid 'nfc_get_handover_sel' command - two arguments "
+ "are required.\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
+ argv[0], argv[1]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long NFC_GET_HANDOVER_SEL command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
#endif /* CONFIG_WPS_NFC */
@@ -796,6 +819,7 @@
{ "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 },
+ { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
#endif /* CONFIG_WPS_NFC */
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
{ "wps_config", hostapd_cli_cmd_wps_config },
diff --git a/hostapd/wps-ap-nfc.py b/hostapd/wps-ap-nfc.py
new file mode 100755
index 0000000..32a0214
--- /dev/null
+++ b/hostapd/wps-ap-nfc.py
@@ -0,0 +1,273 @@
+#!/usr/bin/python
+#
+# Example nfcpy to hostapd wrapper for WPS NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import logging
+logging.basicConfig()
+
+import wpactrl
+
+wpas_ctrl = '/var/run/hostapd'
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError, error:
+ print "Could not find hostapd: ", error
+ return None
+
+ if len(ifaces) < 1:
+ print "No hostapd control interface found"
+ return None
+
+ for ctrl in ifaces:
+ try:
+ wpas = wpactrl.WPACtrl(ctrl)
+ return wpas
+ except wpactrl.error, error:
+ print "Error: ", error
+ pass
+ return None
+
+
+def wpas_tag_read(message):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return
+ print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
+
+
+def wpas_get_config_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_password_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_handover_sel():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
+
+
+def wpas_report_handover(req, sel):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
+ str(req).encode("hex") + " " +
+ str(sel).encode("hex"))
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self):
+ super(HandoverServer, self).__init__()
+
+ def process_request(self, request):
+ print "HandoverServer - request received"
+ print "Parsed handover request: " + request.pretty()
+
+ sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+ for carrier in request.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.wsc":
+ print "WPS carrier type match - add WPS carrier record"
+ self.received_carrier = carrier.record
+ data = wpas_get_handover_sel()
+ if data is None:
+ print "Could not get handover select carrier record from hostapd"
+ continue
+ print "Handover select carrier record from hostapd:"
+ print data.encode("hex")
+ self.sent_carrier = data
+
+ message = nfc.ndef.Message(data);
+ sel.add_carrier(message[0], "active", message[1:])
+
+ print "Handover select:"
+ print sel.pretty()
+ print str(sel).encode("hex")
+
+ print "Sending handover select"
+ return sel
+
+
+def wps_handover_resp(peer):
+ print "Trying to handle WPS handover"
+
+ srv = HandoverServer()
+
+ nfc.llcp.activate(peer);
+
+ try:
+ print "Trying handover";
+ srv.start()
+ print "Wait for disconnect"
+ while nfc.llcp.connected():
+ time.sleep(0.1)
+ print "Disconnected after handover"
+ except nfc.llcp.ConnectRefused:
+ print "Handover connection refused"
+ nfc.llcp.shutdown()
+ return
+
+ if srv.sent_carrier:
+ wpas_report_handover(srv.received_carrier, srv.sent_carrier)
+
+ print "Remove peer"
+ nfc.llcp.shutdown()
+ print "Done with handover"
+
+
+def wps_tag_read(tag):
+ if len(tag.ndef.message):
+ message = nfc.ndef.Message(tag.ndef.message)
+ print "message type " + message.type
+
+ for record in message:
+ print "record type " + record.type
+ if record.type == "application/vnd.wfa.wsc":
+ print "WPS tag - send to hostapd"
+ wpas_tag_read(tag.ndef.message)
+ break
+ else:
+ print "Empty tag"
+
+ print "Remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def wps_write_config_tag(clf):
+ print "Write WPS config token"
+ data = wpas_get_config_token()
+ if (data == None):
+ print "Could not get WPS config token from hostapd"
+ return
+
+ print "Touch an NFC tag"
+ while True:
+ tag = clf.poll()
+ if tag == None:
+ time.sleep(0.1)
+ continue
+ break
+
+ print "Tag found - writing"
+ tag.ndef.message = data
+ print "Done - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def wps_write_password_tag(clf):
+ print "Write WPS password token"
+ data = wpas_get_password_token()
+ if (data == None):
+ print "Could not get WPS password token from hostapd"
+ return
+
+ print "Touch an NFC tag"
+ while True:
+ tag = clf.poll()
+ if tag == None:
+ time.sleep(0.1)
+ continue
+ break
+
+ print "Tag found - writing"
+ tag.ndef.message = data
+ print "Done - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def find_peer(clf):
+ while True:
+ if nfc.llcp.connected():
+ print "LLCP connected"
+ general_bytes = nfc.llcp.startup({})
+ peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
+ if isinstance(peer, nfc.DEP):
+ print "listen -> DEP";
+ if peer.general_bytes.startswith("Ffm"):
+ print "Found DEP"
+ return peer
+ print "mismatch in general_bytes"
+ print peer.general_bytes
+
+ peer = clf.poll(general_bytes)
+ if isinstance(peer, nfc.DEP):
+ print "poll -> DEP";
+ if peer.general_bytes.startswith("Ffm"):
+ print "Found DEP"
+ return peer
+ print "mismatch in general_bytes"
+ print peer.general_bytes
+
+ if peer:
+ print "Found tag"
+ return peer
+
+
+def main():
+ clf = nfc.ContactlessFrontend()
+
+ try:
+ if len(sys.argv) > 1 and sys.argv[1] == "write-config":
+ wps_write_config_tag(clf)
+ raise SystemExit
+
+ if len(sys.argv) > 1 and sys.argv[1] == "write-password":
+ wps_write_password_tag(clf)
+ raise SystemExit
+
+ while True:
+ print "Waiting for a tag or peer to be touched"
+
+ tag = find_peer(clf)
+ if isinstance(tag, nfc.DEP):
+ wps_handover_resp(tag)
+ continue
+
+ if tag.ndef:
+ wps_tag_read(tag)
+ continue
+
+ print "Not an NDEF tag - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+ except KeyboardInterrupt:
+ raise SystemExit
+ finally:
+ clf.close()
+
+ raise SystemExit
+
+if __name__ == '__main__':
+ main()
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 4742107..6606f72 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -365,6 +365,7 @@
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ int wps_nfc_pw_from_config;
int wps_nfc_dev_pw_id;
struct wpabuf *wps_nfc_dh_pubkey;
struct wpabuf *wps_nfc_dh_privkey;
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 8980bec..6d22d49 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -13,6 +13,7 @@
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -393,6 +394,22 @@
}
+void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
+ const u8 *addr, int reason_code)
+{
+ switch (reason_code) {
+ case MAX_CLIENT_REACHED:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR,
+ MAC2STR(addr));
+ break;
+ case BLOCKED_CLIENT:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR,
+ MAC2STR(addr));
+ break;
+ }
+}
+
+
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,
int ssi_signal)
@@ -828,6 +845,13 @@
data->ch_switch.ht_enabled,
data->ch_switch.ch_offset);
break;
+ case EVENT_CONNECT_FAILED_REASON:
+ if (!data)
+ break;
+ hostapd_event_connect_failed_reason(
+ hapd, data->connect_failed_reason.addr,
+ data->connect_failed_reason.code);
+ break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 2827232..8ab4f3e 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -305,6 +305,8 @@
const u8 *ie, size_t ielen, int reassoc);
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
+void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
+ const u8 *addr, int reason_code);
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,
int ssi_signal);
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 923b698..37112bd 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -443,7 +443,6 @@
iface->conf->channel +
iface->conf->secondary_channel * 4);
iface->conf->secondary_channel = 0;
- iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
}
res = ieee80211n_allowed_ht40_channel_pair(iface);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 129c5b5..8baa15e 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1601,7 +1601,7 @@
hapd->iface->freq);
}
if (hapd->public_action_cb2) {
- hapd->public_action_cb2(hapd->public_action_cb_ctx,
+ hapd->public_action_cb2(hapd->public_action_cb2_ctx,
(u8 *) mgmt, len,
hapd->iface->freq);
}
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 6c3696f..6483e1c 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -133,8 +133,7 @@
new_op_mode = 0;
if (iface->num_sta_no_ht)
new_op_mode = OP_MODE_MIXED;
- else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
- && iface->num_sta_ht_20mhz)
+ else if (iface->conf->secondary_channel && iface->num_sta_ht_20mhz)
new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
else if (iface->olbc_ht)
new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 5ce4f1b..dfe77ad 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1583,8 +1583,25 @@
}
+struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef)
+{
+ /*
+ * Handover Select carrier record for WPS uses the same format as
+ * configuration token.
+ */
+ return hostapd_wps_nfc_config_token(hapd, ndef);
+}
+
+
struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
{
+ if (hapd->conf->wps_nfc_pw_from_config) {
+ return wps_nfc_token_build(ndef,
+ hapd->conf->wps_nfc_dev_pw_id,
+ hapd->conf->wps_nfc_dh_pubkey,
+ hapd->conf->wps_nfc_dev_pw);
+ }
+
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,
diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h
index 4e5026b..a2c2cf0 100644
--- a/src/ap/wps_hostapd.h
+++ b/src/ap/wps_hostapd.h
@@ -35,6 +35,7 @@
const struct wpabuf *data);
struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
int ndef);
+struct wpabuf * hostapd_wps_nfc_hs_cr(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);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index f72c0d4..6a7fff6 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -218,6 +218,7 @@
/* EIDs defined by IEEE 802.11h - END */
#define WLAN_EID_ERP_INFO 42
#define WLAN_EID_HT_CAP 45
+#define WLAN_EID_QOS 46
#define WLAN_EID_RSN 48
#define WLAN_EID_EXT_SUPP_RATES 50
#define WLAN_EID_MOBILITY_DOMAIN 54
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 84f1195..77c48cf 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -150,6 +150,8 @@
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
+#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
+#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
/* BSS command information masks */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 5e8fd65..5dee2e6 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -122,6 +122,13 @@
#define IEEE80211_CAP_IBSS 0x0002
#define IEEE80211_CAP_PRIVACY 0x0010
+/* DMG (60 GHz) IEEE 802.11ad */
+/* type - bits 0..1 */
+#define IEEE80211_CAP_DMG_MASK 0x0003
+#define IEEE80211_CAP_DMG_IBSS 0x0001 /* Tx by: STA */
+#define IEEE80211_CAP_DMG_PBSS 0x0002 /* Tx by: PCP */
+#define IEEE80211_CAP_DMG_AP 0x0003 /* Tx by: AP */
+
#define WPA_SCAN_QUAL_INVALID BIT(0)
#define WPA_SCAN_NOISE_INVALID BIT(1)
#define WPA_SCAN_LEVEL_INVALID BIT(2)
@@ -180,10 +187,12 @@
* struct wpa_scan_results - Scan results
* @res: Array of pointers to allocated variable length scan result entries
* @num: Number of entries in the scan result array
+ * @fetch_time: Time when the results were fetched from the driver
*/
struct wpa_scan_results {
struct wpa_scan_res **res;
size_t num;
+ struct os_time fetch_time;
};
/**
@@ -902,6 +911,8 @@
u32 flags; /* bitmask of WPA_STA_* flags */
int set; /* Set STA parameters instead of add */
u8 qosinfo;
+ const u8 *ext_capab;
+ size_t ext_capab_len;
};
struct hostapd_freq_params {
@@ -3067,7 +3078,16 @@
*
* This event can be used to request a WNM operation to be performed.
*/
- EVENT_WNM
+ EVENT_WNM,
+
+ /**
+ * EVENT_CONNECT_FAILED_REASON - Connection failure reason in AP mode
+ *
+ * This event indicates that the driver reported a connection failure
+ * with the specified client (for example, max client reached, etc.) in
+ * AP mode.
+ */
+ EVENT_CONNECT_FAILED_REASON
};
@@ -3692,6 +3712,19 @@
int ht_enabled;
int ch_offset;
} ch_switch;
+
+ /**
+ * struct connect_failed - Data for EVENT_CONNECT_FAILED_REASON
+ * @addr: Remote client address
+ * @code: Reason code for connection failure
+ */
+ struct connect_failed_reason {
+ u8 addr[ETH_ALEN];
+ enum {
+ MAX_CLIENT_REACHED,
+ BLOCKED_CLIENT
+ } code;
+ } connect_failed_reason;
};
/**
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 418cf1a..565a01b 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -79,6 +79,7 @@
E2S(EAPOL_TX_STATUS);
E2S(CH_SWITCH);
E2S(WNM);
+ E2S(CONNECT_FAILED_REASON);
}
return "UNKNOWN";
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index d133bad..a134992 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2162,6 +2162,43 @@
}
+static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+ u32 reason;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.connect_failed_reason.addr,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
+ switch (reason) {
+ case NL80211_CONN_FAIL_MAX_CLIENTS:
+ wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
+ data.connect_failed_reason.code = MAX_CLIENT_REACHED;
+ break;
+ case NL80211_CONN_FAIL_BLOCKED_CLIENT:
+ wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
+ " tried to connect",
+ MAC2STR(data.connect_failed_reason.addr));
+ data.connect_failed_reason.code = BLOCKED_CLIENT;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
+ "%u", reason);
+ return;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
+}
+
+
static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
int wds)
{
@@ -2299,6 +2336,9 @@
case NL80211_CMD_TDLS_OPER:
nl80211_tdls_oper_event(drv, tb);
break;
+ case NL80211_CMD_CONN_FAILED:
+ nl80211_connect_failed_event(drv, tb);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
@@ -5798,6 +5838,8 @@
if (!msg)
return -ENOMEM;
+ wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
+ params->set ? "Set" : "Add", MAC2STR(params->addr));
nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
NL80211_CMD_NEW_STATION);
@@ -5805,26 +5847,49 @@
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
params->supp_rates);
+ wpa_hexdump(MSG_DEBUG, " * supported rates", params->supp_rates,
+ params->supp_rates_len);
if (!params->set) {
+ wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+ wpa_printf(MSG_DEBUG, " * listen_interval=%u",
+ params->listen_interval);
NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
params->listen_interval);
}
if (params->ht_capabilities) {
+ wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
+ (u8 *) params->ht_capabilities,
+ sizeof(*params->ht_capabilities));
NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
sizeof(*params->ht_capabilities),
params->ht_capabilities);
}
if (params->vht_capabilities) {
+ wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
+ (u8 *) params->vht_capabilities,
+ sizeof(*params->vht_capabilities));
NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY,
sizeof(*params->vht_capabilities),
params->vht_capabilities);
}
+ wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
+
+ if (params->ext_capab) {
+ wpa_hexdump(MSG_DEBUG, " * ext_capab",
+ params->ext_capab, params->ext_capab_len);
+ NLA_PUT(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
+ params->ext_capab_len, params->ext_capab);
+ }
+
os_memset(&upd, 0, sizeof(upd));
upd.mask = sta_flags_nl80211(params->flags);
upd.set = upd.mask;
+ wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
+ upd.set, upd.mask);
NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
if (params->flags & WPA_STA_WMM) {
@@ -5832,10 +5897,11 @@
if (!wme)
goto nla_put_failure;
+ wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
- (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
+ (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
WMM_QOSINFO_STA_SP_MASK);
if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
goto nla_put_failure;
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index bd65dd8..c99802a 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1318,11 +1318,12 @@
if (drv->pending_p2p_scan && drv->p2p) {
#ifdef CONFIG_P2P
size_t i;
+ struct os_time now;
+ os_get_time(&now);
for (i = 0; i < drv->num_scanres; i++) {
struct wpa_scan_res *bss = drv->scanres[i];
if (p2p_scan_res_handler(drv->p2p, bss->bssid,
- bss->freq, bss->age,
- bss->level,
+ bss->freq, &now, bss->level,
(const u8 *) (bss + 1),
bss->ie_len) > 0)
return;
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index e3e19f8..c46bb01 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -170,7 +170,8 @@
* %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 and %NL80211_ATTR_INACTIVITY_TIMEOUT.
+ * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT,
+ * %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS.
* The channel to use can be set on the interface or be given using the
* %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
@@ -374,8 +375,8 @@
* requests to connect to a specified network but without separating
* auth and assoc steps. For this, you need to specify the SSID in a
* %NL80211_ATTR_SSID attribute, and can optionally specify the association
- * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
- * %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
+ * %NL80211_ATTR_MAC, %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
@@ -512,6 +513,12 @@
* command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
* more background information, see
* http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ * The @NL80211_CMD_SET_WOWLAN command can also be used as a notification
+ * from the driver reporting the wakeup reason. In this case, the
+ * @NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason
+ * for the wakeup, if it was caused by wireless. If it is not present
+ * in the wakeup notification, the wireless device didn't cause the
+ * wakeup but reports that it was woken up.
*
* @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
* the necessary information for supporting GTK rekey offload. This
@@ -586,6 +593,24 @@
* @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames
* for IBSS or MESH vif.
*
+ * @NL80211_CMD_SET_MAC_ACL: sets ACL for MAC address based access control.
+ * This is to be used with the drivers advertising the support of MAC
+ * address based access control. List of MAC addresses is passed in
+ * %NL80211_ATTR_MAC_ADDRS and ACL policy is passed in
+ * %NL80211_ATTR_ACL_POLICY. Driver will enable ACL with this list, if it
+ * is not already done. The new list will replace any existing list. Driver
+ * will clear its ACL when the list of MAC addresses passed is empty. This
+ * command is used in AP/P2P GO mode. Driver has to make sure to clear its
+ * ACL list during %NL80211_CMD_STOP_AP.
+ *
+ * @NL80211_CMD_RADAR_DETECT: Start a Channel availability check (CAC). Once
+ * a radar is detected or the channel availability scan (CAC) has finished
+ * or was aborted, or a radar was detected, usermode will be notified with
+ * this event. This command is also used to notify userspace about radars
+ * while operating on this channel.
+ * %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the
+ * event.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -736,6 +761,10 @@
NL80211_CMD_SET_MCAST_RATE,
+ NL80211_CMD_SET_MAC_ACL,
+
+ NL80211_CMD_RADAR_DETECT,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -958,7 +987,7 @@
* @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
* used for the association (&enum nl80211_mfp, represented as a u32);
* this attribute can be used
- * with %NL80211_CMD_ASSOCIATE request
+ * with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests
*
* @NL80211_ATTR_STA_FLAGS2: Attribute containing a
* &struct nl80211_sta_flag_update.
@@ -1310,6 +1339,35 @@
* if not given in START_AP 0 is assumed, if not given in SET_BSS
* no change is made.
*
+ * @NL80211_ATTR_LOCAL_MESH_POWER_MODE: local mesh STA link-specific power mode
+ * defined in &enum nl80211_mesh_power_mode.
+ *
+ * @NL80211_ATTR_ACL_POLICY: ACL policy, see &enum nl80211_acl_policy,
+ * carried in a u32 attribute
+ *
+ * @NL80211_ATTR_MAC_ADDRS: Array of nested MAC addresses, used for
+ * MAC ACL.
+ *
+ * @NL80211_ATTR_MAC_ACL_MAX: u32 attribute to advertise the maximum
+ * number of MAC addresses that a device can support for MAC
+ * ACL.
+ *
+ * @NL80211_ATTR_RADAR_EVENT: Type of radar event for notification to userspace,
+ * contains a value of enum nl80211_radar_event (u32).
+ *
+ * @NL80211_ATTR_EXT_CAPA: 802.11 extended capabilities that the kernel driver
+ * has and handles. The format is the same as the IE contents. See
+ * 802.11-2012 8.4.2.29 for more information.
+ * @NL80211_ATTR_EXT_CAPA_MASK: Extended capabilities that the kernel driver
+ * has set in the %NL80211_ATTR_EXT_CAPA value, for multibit fields.
+ *
+ * @NL80211_ATTR_STA_CAPABILITY: Station capabilities (u16) are advertised to
+ * the driver, e.g., to enable TDLS power save (PU-APSD).
+ *
+ * @NL80211_ATTR_STA_EXT_CAPABILITY: Station extended capabilities are
+ * advertised to the driver, e.g., to enable TDLS off channel operations
+ * and PU-APSD.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1580,6 +1638,22 @@
NL80211_ATTR_P2P_CTWINDOW,
NL80211_ATTR_P2P_OPPPS,
+ NL80211_ATTR_LOCAL_MESH_POWER_MODE,
+
+ NL80211_ATTR_ACL_POLICY,
+
+ NL80211_ATTR_MAC_ADDRS,
+
+ NL80211_ATTR_MAC_ACL_MAX,
+
+ NL80211_ATTR_RADAR_EVENT,
+
+ NL80211_ATTR_EXT_CAPA,
+ NL80211_ATTR_EXT_CAPA_MASK,
+
+ NL80211_ATTR_STA_CAPABILITY,
+ NL80211_ATTR_STA_EXT_CAPABILITY,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1697,6 +1771,9 @@
* flag can't be changed, it is only valid while adding a station, and
* attempts to change it will silently be ignored (rather than rejected
* as errors.)
+ * @NL80211_STA_FLAG_ASSOCIATED: station is associated; used with drivers
+ * that support %NL80211_FEATURE_FULL_AP_CLIENT_STATE to transition a
+ * previously added station into associated state
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined
* @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
@@ -1708,6 +1785,7 @@
NL80211_STA_FLAG_MFP,
NL80211_STA_FLAG_AUTHENTICATED,
NL80211_STA_FLAG_TDLS_PEER,
+ NL80211_STA_FLAG_ASSOCIATED,
/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
@@ -1813,6 +1891,8 @@
* @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
* @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
* @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @NL80211_STA_INFO_RX_BYTES64: total received bytes (u64, from this station)
+ * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (u64, to this station)
* @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
* @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
* containing info as possible, see &enum nl80211_rate_info
@@ -1834,6 +1914,10 @@
* @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_LOCAL_PM: local mesh STA link-specific power mode
+ * @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode
+ * @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards
+ * non-peer STA
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -1858,6 +1942,11 @@
NL80211_STA_INFO_STA_FLAGS,
NL80211_STA_INFO_BEACON_LOSS,
NL80211_STA_INFO_T_OFFSET,
+ NL80211_STA_INFO_LOCAL_PM,
+ NL80211_STA_INFO_PEER_PM,
+ NL80211_STA_INFO_NONPEER_PM,
+ NL80211_STA_INFO_RX_BYTES64,
+ NL80211_STA_INFO_TX_BYTES64,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -1967,6 +2056,20 @@
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
* (100 * dBm).
+ * @NL80211_FREQUENCY_ATTR_DFS_STATE: current state for DFS
+ * (enum nl80211_dfs_state)
+ * @NL80211_FREQUENCY_ATTR_DFS_TIME: time in miliseconds for how long
+ * this channel is in this DFS state.
+ * @NL80211_FREQUENCY_ATTR_NO_HT40_MINUS: HT40- isn't possible with this
+ * channel as the control channel
+ * @NL80211_FREQUENCY_ATTR_NO_HT40_PLUS: HT40+ isn't possible with this
+ * channel as the control channel
+ * @NL80211_FREQUENCY_ATTR_NO_80MHZ: any 80 MHz channel using this channel
+ * as the primary or any of the secondary channels isn't possible,
+ * this includes 80+80 channels
+ * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel
+ * using this channel as the primary or any of the secondary channels
+ * isn't possible
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -1979,6 +2082,12 @@
NL80211_FREQUENCY_ATTR_NO_IBSS,
NL80211_FREQUENCY_ATTR_RADAR,
NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+ NL80211_FREQUENCY_ATTR_DFS_STATE,
+ NL80211_FREQUENCY_ATTR_DFS_TIME,
+ NL80211_FREQUENCY_ATTR_NO_HT40_MINUS,
+ NL80211_FREQUENCY_ATTR_NO_HT40_PLUS,
+ NL80211_FREQUENCY_ATTR_NO_80MHZ,
+ NL80211_FREQUENCY_ATTR_NO_160MHZ,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -2249,6 +2358,34 @@
};
/**
+ * enum nl80211_mesh_power_mode - mesh power save modes
+ *
+ * @NL80211_MESH_POWER_UNKNOWN: The mesh power mode of the mesh STA is
+ * not known or has not been set yet.
+ * @NL80211_MESH_POWER_ACTIVE: Active mesh power mode. The mesh STA is
+ * in Awake state all the time.
+ * @NL80211_MESH_POWER_LIGHT_SLEEP: Light sleep mode. The mesh STA will
+ * alternate between Active and Doze states, but will wake up for
+ * neighbor's beacons.
+ * @NL80211_MESH_POWER_DEEP_SLEEP: Deep sleep mode. The mesh STA will
+ * alternate between Active and Doze states, but may not wake up
+ * for neighbor's beacons.
+ *
+ * @__NL80211_MESH_POWER_AFTER_LAST - internal use
+ * @NL80211_MESH_POWER_MAX - highest possible power save level
+ */
+
+enum nl80211_mesh_power_mode {
+ NL80211_MESH_POWER_UNKNOWN,
+ NL80211_MESH_POWER_ACTIVE,
+ NL80211_MESH_POWER_LIGHT_SLEEP,
+ NL80211_MESH_POWER_DEEP_SLEEP,
+
+ __NL80211_MESH_POWER_AFTER_LAST,
+ NL80211_MESH_POWER_MAX = __NL80211_MESH_POWER_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_meshconf_params - mesh configuration parameters
*
* Mesh configuration parameters. These can be changed while the mesh is
@@ -2342,6 +2479,11 @@
* (in TUs) during which a mesh STA can send only one Action frame
* containing a PREQ element for root path confirmation.
*
+ * @NL80211_MESHCONF_POWER_MODE: Default mesh power mode for new peer links.
+ * type &enum nl80211_mesh_power_mode (u32)
+ *
+ * @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs)
+ *
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
*/
enum nl80211_meshconf_params {
@@ -2371,6 +2513,8 @@
NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
+ NL80211_MESHCONF_POWER_MODE,
+ NL80211_MESHCONF_AWAKE_WINDOW,
/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2816,10 +2960,12 @@
* corresponds to the lowest-order bit in the second byte of the mask.
* For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where
* xx indicates "don't care") would be represented by a pattern of
- * twelve zero bytes, and a mask of "0xed,0x07".
+ * twelve zero bytes, and a mask of "0xed,0x01".
* Note that the pattern matching is done as though frames were not
* 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
* first (including SNAP header unpacking) and then matched.
+ * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after
+ * these fixed number of bytes of received packet
* @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
* @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
*/
@@ -2827,6 +2973,7 @@
__NL80211_WOWLAN_PKTPAT_INVALID,
NL80211_WOWLAN_PKTPAT_MASK,
NL80211_WOWLAN_PKTPAT_PATTERN,
+ NL80211_WOWLAN_PKTPAT_OFFSET,
NUM_NL80211_WOWLAN_PKTPAT,
MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
@@ -2837,6 +2984,7 @@
* @max_patterns: maximum number of patterns supported
* @min_pattern_len: minimum length of each pattern
* @max_pattern_len: maximum length of each pattern
+ * @max_pkt_offset: maximum Rx packet offset
*
* This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
* that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
@@ -2846,6 +2994,7 @@
__u32 max_patterns;
__u32 min_pattern_len;
__u32 max_pattern_len;
+ __u32 max_pkt_offset;
} __attribute__((packed));
/**
@@ -2861,12 +3010,17 @@
* @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns
* which are passed in an array of nested attributes, each nested attribute
* defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern.
- * Each pattern defines a wakeup packet. The matching is done on the MSDU,
- * i.e. as though the packet was an 802.3 packet, so the pattern matching
- * is done after the packet is converted to the MSDU.
+ * Each pattern defines a wakeup packet. Packet offset is associated with
+ * each pattern which is used while matching the pattern. The matching is
+ * done on the MSDU, i.e. as though the packet was an 802.3 packet, so the
+ * pattern matching is done after the packet is converted to the MSDU.
*
* In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
* carrying a &struct nl80211_wowlan_pattern_support.
+ *
+ * When reporting wakeup. it is a u32 attribute containing the 0-based
+ * index of the pattern that caused the wakeup, in the patterns passed
+ * to the kernel when configuring.
* @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be
* used when setting, used only to indicate that GTK rekeying is supported
* by the device (flag)
@@ -2877,8 +3031,36 @@
* @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag)
* @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released
* (on devices that have rfkill in the device) (flag)
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211: For wakeup reporting only, contains
+ * the 802.11 packet that caused the wakeup, e.g. a deauth frame. The frame
+ * may be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN
+ * attribute contains the original length.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN: Original length of the 802.11
+ * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211
+ * attribute if the packet was truncated somewhere.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023: For wakeup reporting only, contains the
+ * 802.11 packet that caused the wakeup, e.g. a magic packet. The frame may
+ * be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN attribute
+ * contains the original length.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: Original length of the 802.3
+ * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023
+ * attribute if the packet was truncated somewhere.
+ * @NL80211_WOWLAN_TRIG_TCP_CONNECTION: TCP connection wake, see DOC section
+ * "TCP connection wakeup" for more details. This is a nested attribute
+ * containing the exact information for establishing and keeping alive
+ * the TCP connection.
+ * @NL80211_WOWLAN_TRIG_TCP_WAKEUP_MATCH: For wakeup reporting only, the
+ * wakeup packet was received on the TCP connection
+ * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST: For wakeup reporting only, the
+ * TCP connection was lost or failed to be established
+ * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only,
+ * the TCP connection ran out of tokens to use for data to send to the
+ * service
* @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
* @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
+ *
+ * These nested attributes are used to configure the wakeup triggers and
+ * to report the wakeup reason(s).
*/
enum nl80211_wowlan_triggers {
__NL80211_WOWLAN_TRIG_INVALID,
@@ -2891,6 +3073,14 @@
NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST,
NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE,
NL80211_WOWLAN_TRIG_RFKILL_RELEASE,
+ NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211,
+ NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN,
+ NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023,
+ NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN,
+ NL80211_WOWLAN_TRIG_TCP_CONNECTION,
+ NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH,
+ NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST,
+ NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS,
/* keep last */
NUM_NL80211_WOWLAN_TRIG,
@@ -2898,6 +3088,116 @@
};
/**
+ * DOC: TCP connection wakeup
+ *
+ * Some devices can establish a TCP connection in order to be woken up by a
+ * packet coming in from outside their network segment, or behind NAT. If
+ * configured, the device will establish a TCP connection to the given
+ * service, and periodically send data to that service. The first data
+ * packet is usually transmitted after SYN/ACK, also ACKing the SYN/ACK.
+ * The data packets can optionally include a (little endian) sequence
+ * number (in the TCP payload!) that is generated by the device, and, also
+ * optionally, a token from a list of tokens. This serves as a keep-alive
+ * with the service, and for NATed connections, etc.
+ *
+ * During this keep-alive period, the server doesn't send any data to the
+ * client. When receiving data, it is compared against the wakeup pattern
+ * (and mask) and if it matches, the host is woken up. Similarly, if the
+ * connection breaks or cannot be established to start with, the host is
+ * also woken up.
+ *
+ * Developer's note: ARP offload is required for this, otherwise TCP
+ * response packets might not go through correctly.
+ */
+
+/**
+ * struct nl80211_wowlan_tcp_data_seq - WoWLAN TCP data sequence
+ * @start: starting value
+ * @offset: offset of sequence number in packet
+ * @len: length of the sequence value to write, 1 through 4
+ *
+ * Note: don't confuse with the TCP sequence number(s), this is for the
+ * keepalive packet payload. The actual value is written into the packet
+ * in little endian.
+ */
+struct nl80211_wowlan_tcp_data_seq {
+ __u32 start, offset, len;
+};
+
+/**
+ * struct nl80211_wowlan_tcp_data_token - WoWLAN TCP data token config
+ * @offset: offset of token in packet
+ * @len: length of each token
+ * @token_stream: stream of data to be used for the tokens, the length must
+ * be a multiple of @len for this to make sense
+ */
+struct nl80211_wowlan_tcp_data_token {
+ __u32 offset, len;
+ __u8 token_stream[];
+};
+
+/**
+ * struct nl80211_wowlan_tcp_data_token_feature - data token features
+ * @min_len: minimum token length
+ * @max_len: maximum token length
+ * @bufsize: total available token buffer size (max size of @token_stream)
+ */
+struct nl80211_wowlan_tcp_data_token_feature {
+ __u32 min_len, max_len, bufsize;
+};
+
+/**
+ * enum nl80211_wowlan_tcp_attrs - WoWLAN TCP connection parameters
+ * @__NL80211_WOWLAN_TCP_INVALID: invalid number for nested attributes
+ * @NL80211_WOWLAN_TCP_SRC_IPV4: source IPv4 address (in network byte order)
+ * @NL80211_WOWLAN_TCP_DST_IPV4: destination IPv4 address
+ * (in network byte order)
+ * @NL80211_WOWLAN_TCP_DST_MAC: destination MAC address, this is given because
+ * route lookup when configured might be invalid by the time we suspend,
+ * and doing a route lookup when suspending is no longer possible as it
+ * might require ARP querying.
+ * @NL80211_WOWLAN_TCP_SRC_PORT: source port (u16); optional, if not given a
+ * socket and port will be allocated
+ * @NL80211_WOWLAN_TCP_DST_PORT: destination port (u16)
+ * @NL80211_WOWLAN_TCP_DATA_PAYLOAD: data packet payload, at least one byte.
+ * For feature advertising, a u32 attribute holding the maximum length
+ * of the data payload.
+ * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ: data packet sequence configuration
+ * (if desired), a &struct nl80211_wowlan_tcp_data_seq. For feature
+ * advertising it is just a flag
+ * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN: data packet token configuration,
+ * see &struct nl80211_wowlan_tcp_data_token and for advertising see
+ * &struct nl80211_wowlan_tcp_data_token_feature.
+ * @NL80211_WOWLAN_TCP_DATA_INTERVAL: data interval in seconds, maximum
+ * interval in feature advertising (u32)
+ * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a
+ * u32 attribute holding the maximum length
+ * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for
+ * feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK
+ * but on the TCP payload only.
+ * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes
+ * @MAX_NL80211_WOWLAN_TCP: highest attribute number
+ */
+enum nl80211_wowlan_tcp_attrs {
+ __NL80211_WOWLAN_TCP_INVALID,
+ NL80211_WOWLAN_TCP_SRC_IPV4,
+ NL80211_WOWLAN_TCP_DST_IPV4,
+ NL80211_WOWLAN_TCP_DST_MAC,
+ NL80211_WOWLAN_TCP_SRC_PORT,
+ NL80211_WOWLAN_TCP_DST_PORT,
+ NL80211_WOWLAN_TCP_DATA_PAYLOAD,
+ NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
+ NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
+ NL80211_WOWLAN_TCP_DATA_INTERVAL,
+ NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
+ NL80211_WOWLAN_TCP_WAKE_MASK,
+
+ /* keep last */
+ NUM_NL80211_WOWLAN_TCP,
+ MAX_NL80211_WOWLAN_TCP = NUM_NL80211_WOWLAN_TCP - 1
+};
+
+/**
* enum nl80211_iface_limit_attrs - limit attributes
* @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
* @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
@@ -2933,6 +3233,8 @@
* the infrastructure network's beacon interval.
* @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many
* different channels may be used within this group.
+ * @NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u32 attribute containing the bitmap
+ * of supported channel widths for radar detection.
* @NUM_NL80211_IFACE_COMB: number of attributes
* @MAX_NL80211_IFACE_COMB: highest attribute number
*
@@ -2965,6 +3267,7 @@
NL80211_IFACE_COMB_MAXNUM,
NL80211_IFACE_COMB_STA_AP_BI_MATCH,
NL80211_IFACE_COMB_NUM_CHANNELS,
+ NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
/* keep last */
NUM_NL80211_IFACE_COMB,
@@ -3140,6 +3443,19 @@
* setting
* @NL80211_FEATURE_P2P_GO_OPPPS: P2P GO implementation supports opportunistic
* powersave
+ * @NL80211_FEATURE_FULL_AP_CLIENT_STATE: The driver supports full state
+ * transitions for AP clients. Without this flag (and if the driver
+ * doesn't have the AP SME in the device) the driver supports adding
+ * stations only when they're associated and adds them in associated
+ * state (to later be transitioned into authorized), with this flag
+ * they should be added before even sending the authentication reply
+ * and then transitioned into authenticated, associated and authorized
+ * states using station flags.
+ * Note that even for drivers that support this, the default is to add
+ * stations in authenticated/associated state, so to add unauthenticated
+ * stations the authenticated/associated bits have to be set in the mask.
+ * @NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: cfg80211 advertises channel limits
+ * (HT40, VHT 80/160 MHz) if this flag is set
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@@ -3155,6 +3471,9 @@
NL80211_FEATURE_NEED_OBSS_SCAN = 1 << 10,
NL80211_FEATURE_P2P_GO_CTWIN = 1 << 11,
NL80211_FEATURE_P2P_GO_OPPPS = 1 << 12,
+ /* bit 13 is reserved */
+ NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14,
+ NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
};
/**
@@ -3182,7 +3501,7 @@
* enum nl80211_connect_failed_reason - connection request failed reasons
* @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be
* handled by the AP is reached.
- * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Client's MAC is in the AP's blocklist.
+ * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Connection request is rejected due to ACL.
*/
enum nl80211_connect_failed_reason {
NL80211_CONN_FAIL_MAX_CLIENTS,
@@ -3210,4 +3529,62 @@
NL80211_SCAN_FLAG_AP = 1<<2,
};
+/**
+ * enum nl80211_acl_policy - access control policy
+ *
+ * Access control policy is applied on a MAC list set by
+ * %NL80211_CMD_START_AP and %NL80211_CMD_SET_MAC_ACL, to
+ * be used with %NL80211_ATTR_ACL_POLICY.
+ *
+ * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are
+ * listed in ACL, i.e. allow all the stations which are not listed
+ * in ACL to authenticate.
+ * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow the stations which are listed
+ * in ACL, i.e. deny all the stations which are not listed in ACL.
+ */
+enum nl80211_acl_policy {
+ NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED,
+ NL80211_ACL_POLICY_DENY_UNLESS_LISTED,
+};
+
+/**
+ * enum nl80211_radar_event - type of radar event for DFS operation
+ *
+ * Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace
+ * about detected radars or success of the channel available check (CAC)
+ *
+ * @NL80211_RADAR_DETECTED: A radar pattern has been detected. The channel is
+ * now unusable.
+ * @NL80211_RADAR_CAC_FINISHED: Channel Availability Check has been finished,
+ * the channel is now available.
+ * @NL80211_RADAR_CAC_ABORTED: Channel Availability Check has been aborted, no
+ * change to the channel status.
+ * @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is
+ * over, channel becomes usable.
+ */
+enum nl80211_radar_event {
+ NL80211_RADAR_DETECTED,
+ NL80211_RADAR_CAC_FINISHED,
+ NL80211_RADAR_CAC_ABORTED,
+ NL80211_RADAR_NOP_FINISHED,
+};
+
+/**
+ * enum nl80211_dfs_state - DFS states for channels
+ *
+ * Channel states used by the DFS code.
+ *
+ * @IEEE80211_DFS_USABLE: The channel can be used, but channel availability
+ * check (CAC) must be performed before using it for AP or IBSS.
+ * @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
+ * is therefore marked as not available.
+ * @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
+ */
+
+enum nl80211_dfs_state {
+ NL80211_DFS_USABLE,
+ NL80211_DFS_UNAVAILABLE,
+ NL80211_DFS_AVAILABLE,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/eap_gpsk_common.c b/src/eap_common/eap_gpsk_common.c
index 7d106dd..7a33215 100644
--- a/src/eap_common/eap_gpsk_common.c
+++ b/src/eap_common/eap_gpsk_common.c
@@ -340,6 +340,141 @@
}
+static int eap_gpsk_derive_mid_helper(u32 csuite_specifier,
+ u8 *kdf_out, size_t kdf_out_len,
+ const u8 *psk, const u8 *seed,
+ size_t seed_len, u8 method_type)
+{
+ u8 *pos, *data;
+ size_t data_len;
+ int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len,
+ u8 *buf, size_t len);
+
+ gkdf = NULL;
+ switch (csuite_specifier) {
+ case EAP_GPSK_CIPHER_AES:
+ gkdf = eap_gpsk_gkdf_cmac;
+ break;
+#ifdef EAP_GPSK_SHA256
+ case EAP_GPSK_CIPHER_SHA256:
+ gkdf = eap_gpsk_gkdf_sha256;
+ break;
+#endif /* EAP_GPSK_SHA256 */
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d used in "
+ "Session-Id derivation", csuite_specifier);
+ return -1;
+ }
+
+#define SID_LABEL "Method ID"
+ /* "Method ID" || EAP_Method_Type || CSuite_Sel || inputString */
+ data_len = strlen(SID_LABEL) + 1 + 6 + seed_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ os_memcpy(pos, SID_LABEL, strlen(SID_LABEL));
+ pos += strlen(SID_LABEL);
+#undef SID_LABEL
+ os_memcpy(pos, &method_type, 1);
+ pos += 1;
+ WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */
+ pos += 4;
+ WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */
+ pos += 2;
+ os_memcpy(pos, seed, seed_len); /* inputString */
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Data to Method ID derivation",
+ data, data_len);
+
+ if (gkdf(psk, data, data_len, kdf_out, kdf_out_len) < 0) {
+ os_free(data);
+ return -1;
+ }
+ os_free(data);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Method ID", kdf_out, kdf_out_len);
+
+ return 0;
+}
+
+
+/**
+ * eap_gpsk_session_id - Derive EAP-GPSK Session ID
+ * @psk: Pre-shared key
+ * @psk_len: Length of psk in bytes
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @rand_peer: 32-byte RAND_Peer
+ * @rand_server: 32-byte RAND_Server
+ * @id_peer: ID_Peer
+ * @id_peer_len: Length of ID_Peer
+ * @id_server: ID_Server
+ * @id_server_len: Length of ID_Server
+ * @method_type: EAP Authentication Method Type
+ * @sid: Buffer for 17-byte Session ID
+ * @sid_len: Buffer for returning length of Session ID
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
+ int specifier,
+ const u8 *rand_peer, const u8 *rand_server,
+ const u8 *id_peer, size_t id_peer_len,
+ const u8 *id_server, size_t id_server_len,
+ u8 method_type, u8 *sid, size_t *sid_len)
+{
+ u8 *seed, *pos;
+ u8 kdf_out[16];
+ size_t seed_len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving Session ID(%d:%d)",
+ vendor, specifier);
+
+ if (vendor != EAP_GPSK_VENDOR_IETF)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
+
+ /*
+ * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
+ * (= seed)
+ * KS = 16, CSuite_Sel = 0x00000000 0x0001
+ * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
+ * CSuite_Sel || inputString)
+ */
+ seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len;
+ seed = os_malloc(seed_len);
+ if (seed == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
+ "for Session-Id derivation");
+ return -1;
+ }
+
+ pos = seed;
+ os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ os_memcpy(pos, id_peer, id_peer_len);
+ pos += id_peer_len;
+ os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ os_memcpy(pos, id_server, id_server_len);
+ pos += id_server_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
+
+ ret = eap_gpsk_derive_mid_helper(specifier,
+ kdf_out, sizeof(kdf_out),
+ psk, seed, seed_len,
+ method_type);
+
+ sid[0] = method_type;
+ os_memcpy(sid + 1, kdf_out, sizeof(kdf_out));
+ *sid_len = 1 + sizeof(kdf_out);
+
+ os_free(seed);
+
+ return ret;
+}
+
+
/**
* eap_gpsk_mic_len - Get the length of the MIC
* @vendor: CSuite/Vendor
diff --git a/src/eap_common/eap_gpsk_common.h b/src/eap_common/eap_gpsk_common.h
index e3d2b6b..fbcd547 100644
--- a/src/eap_common/eap_gpsk_common.h
+++ b/src/eap_common/eap_gpsk_common.h
@@ -53,6 +53,12 @@
const u8 *id_server, size_t id_server_len,
u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
u8 *pk, size_t *pk_len);
+int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
+ int specifier,
+ const u8 *rand_peer, const u8 *rand_server,
+ const u8 *id_peer, size_t id_peer_len,
+ const u8 *id_server, size_t id_server_len,
+ u8 method_type, u8 *sid, size_t *sid_len);
size_t eap_gpsk_mic_len(int vendor, int specifier);
int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
int specifier, const u8 *data, size_t len, u8 *mic);
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 85c242a..4df8853 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -161,6 +161,8 @@
eapol_set_bool(sm, EAPOL_eapFail, FALSE);
os_free(sm->eapKeyData);
sm->eapKeyData = NULL;
+ os_free(sm->eapSessionId);
+ sm->eapSessionId = NULL;
sm->eapKeyAvailable = FALSE;
eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
sm->lastId = -1; /* new session - make sure this does not match with
@@ -403,6 +405,13 @@
os_free(sm->eapKeyData);
sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
&sm->eapKeyDataLen);
+ os_free(sm->eapSessionId);
+ sm->eapSessionId = sm->m->getSessionId(sm, sm->eap_method_priv,
+ &sm->eapSessionIdLen);
+ if (sm->eapSessionId) {
+ wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
+ sm->eapSessionId, sm->eapSessionIdLen);
+ }
}
}
@@ -1462,6 +1471,8 @@
sm->eapRespData = NULL;
os_free(sm->eapKeyData);
sm->eapKeyData = NULL;
+ os_free(sm->eapSessionId);
+ sm->eapSessionId = NULL;
/* This is not clearly specified in the EAP statemachines draft, but
* it seems necessary to make sure that some of the EAPOL variables get
@@ -2159,6 +2170,28 @@
/**
+ * eap_get_eapSessionId - Get Session-Id from EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Pointer to variable that will be set to number of bytes in the session
+ * Returns: Pointer to the EAP Session-Id or %NULL on failure
+ *
+ * Fetch EAP Session-Id from the EAP state machine. The Session-Id is available
+ * only after a successful authentication. EAP state machine continues to manage
+ * the Session-Id and the caller must not change or free the returned data.
+ */
+const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len)
+{
+ if (sm == NULL || sm->eapSessionId == NULL) {
+ *len = 0;
+ return NULL;
+ }
+
+ *len = sm->eapSessionIdLen;
+ return sm->eapSessionId;
+}
+
+
+/**
* eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @len: Pointer to variable that will be set to number of bytes in the key
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 8bccef1..f87f9b3 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -306,6 +306,7 @@
int eap_key_available(struct eap_sm *sm);
void eap_notify_success(struct eap_sm *sm);
void eap_notify_lower_layer_success(struct eap_sm *sm);
+const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len);
const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
struct wpabuf * eap_get_eapRespData(struct eap_sm *sm);
void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 59861cb..dc424d7 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -1340,6 +1340,28 @@
}
+static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_aka_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = data->eap_method;
+ os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
+ os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_aka_data *data = priv;
@@ -1374,6 +1396,7 @@
eap->process = eap_aka_process;
eap->isKeyAvailable = eap_aka_isKeyAvailable;
eap->getKey = eap_aka_getKey;
+ eap->getSessionId = eap_aka_get_session_id;
eap->has_reauth_data = eap_aka_has_reauth_data;
eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
eap->init_for_reauth = eap_aka_init_for_reauth;
@@ -1404,6 +1427,7 @@
eap->process = eap_aka_process;
eap->isKeyAvailable = eap_aka_isKeyAvailable;
eap->getKey = eap_aka_getKey;
+ eap->getSessionId = eap_aka_get_session_id;
eap->has_reauth_data = eap_aka_has_reauth_data;
eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
eap->init_for_reauth = eap_aka_init_for_reauth;
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 7ca5288..3b8d803 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -53,6 +53,8 @@
int session_ticket_used;
u8 key_data[EAP_FAST_KEY_LEN];
+ u8 *session_id;
+ size_t id_len;
u8 emsk[EAP_EMSK_LEN];
int success;
@@ -238,6 +240,7 @@
pac = pac->next;
eap_fast_free_pac(prev);
}
+ os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
os_free(data);
}
@@ -785,6 +788,21 @@
return NULL;
}
+ if (!data->anon_provisioning && data->phase2_success) {
+ os_free(data->session_id);
+ data->session_id = eap_peer_tls_derive_session_id(
+ sm, &data->ssl, EAP_TYPE_FAST, &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-FAST: Failed to derive "
+ "Session-Id");
+ wpabuf_free(resp);
+ return NULL;
+ }
+ }
+
pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv));
eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *)
pos, _bind, cmk);
@@ -1604,6 +1622,8 @@
os_free(data);
return NULL;
}
+ os_free(data->session_id);
+ data->session_id = NULL;
if (data->phase2_priv && data->phase2_method &&
data->phase2_method->init_for_reauth)
data->phase2_method->init_for_reauth(sm, data->phase2_priv);
@@ -1662,6 +1682,25 @@
}
+static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_fast_data *data = priv;
+ u8 *id;
+
+ if (!data->success)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_fast_data *data = priv;
@@ -1696,6 +1735,7 @@
eap->process = eap_fast_process;
eap->isKeyAvailable = eap_fast_isKeyAvailable;
eap->getKey = eap_fast_getKey;
+ eap->getSessionId = eap_fast_get_session_id;
eap->get_status = eap_fast_get_status;
#if 0
eap->has_reauth_data = eap_fast_has_reauth_data;
diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c
index 2bd0d48..8a0644d 100644
--- a/src/eap_peer/eap_gpsk.c
+++ b/src/eap_peer/eap_gpsk.c
@@ -23,8 +23,8 @@
size_t sk_len;
u8 pk[EAP_GPSK_MAX_PK_LEN];
size_t pk_len;
- u8 session_id;
- int session_id_set;
+ u8 session_id[128];
+ size_t id_len;
u8 *id_peer;
size_t id_peer_len;
u8 *id_server;
@@ -354,6 +354,21 @@
return NULL;
}
+ if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
+ data->vendor, data->specifier,
+ data->rand_peer, data->rand_server,
+ data->id_peer, data->id_peer_len,
+ data->id_server, data->id_server_len,
+ EAP_TYPE_GPSK,
+ data->session_id, &data->id_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
+ eap_gpsk_state(data, FAILURE);
+ wpabuf_free(resp);
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
+ data->session_id, data->id_len);
+
/* No PD_Payload_1 */
wpabuf_put_be16(resp, 0);
@@ -708,6 +723,24 @@
}
+static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_gpsk_data *data = priv;
+ u8 *sid;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ sid = os_malloc(data->id_len);
+ if (sid == NULL)
+ return NULL;
+ os_memcpy(sid, data->session_id, data->id_len);
+ *len = data->id_len;
+
+ return sid;
+}
+
+
int eap_peer_gpsk_register(void)
{
struct eap_method *eap;
@@ -724,6 +757,7 @@
eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
eap->getKey = eap_gpsk_getKey;
eap->get_emsk = eap_gpsk_get_emsk;
+ eap->getSessionId = eap_gpsk_get_session_id;
ret = eap_peer_method_register(eap);
if (ret)
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index dd94317..62c867c 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -261,6 +261,19 @@
* private data or this function may derive the key.
*/
u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
+
+ /**
+ * getSessionId - Get EAP method specific Session-Id
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * @len: Pointer to a variable to store Session-Id length
+ * Returns: Session-Id or %NULL if not available
+ *
+ * This function can be used to get the Session-Id from the EAP method.
+ * The Session-Id may already be stored in the method-specific private
+ * data or this function may derive the Session-Id.
+ */
+ u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
};
@@ -298,6 +311,8 @@
Boolean eapKeyAvailable; /* peer to lower layer */
u8 *eapKeyData; /* peer to lower layer */
size_t eapKeyDataLen; /* peer to lower layer */
+ u8 *eapSessionId; /* peer to lower layer */
+ size_t eapSessionIdLen; /* peer to lower layer */
const struct eap_method *m; /* selected EAP method */
/* not defined in RFC 4137 */
Boolean changed;
diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c
index a227f8b..09a655e 100644
--- a/src/eap_peer/eap_ikev2.c
+++ b/src/eap_peer/eap_ikev2.c
@@ -475,6 +475,36 @@
}
+static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ikev2_data *data = priv;
+ u8 *sid;
+ size_t sid_len;
+ size_t offset;
+
+ if (data->state != DONE || !data->keymat_ok)
+ return NULL;
+
+ sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
+ sid = os_malloc(sid_len);
+ if (sid) {
+ offset = 0;
+ sid[offset] = EAP_TYPE_IKEV2;
+ offset++;
+ os_memcpy(sid + offset, data->ikev2.i_nonce,
+ data->ikev2.i_nonce_len);
+ offset += data->ikev2.i_nonce_len;
+ os_memcpy(sid + offset, data->ikev2.r_nonce,
+ data->ikev2.r_nonce_len);
+ *len = sid_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
+ sid, sid_len);
+ }
+
+ return sid;
+}
+
+
int eap_peer_ikev2_register(void)
{
struct eap_method *eap;
@@ -492,6 +522,7 @@
eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
eap->getKey = eap_ikev2_getKey;
eap->get_emsk = eap_ikev2_get_emsk;
+ eap->getSessionId = eap_ikev2_get_session_id;
ret = eap_peer_method_register(eap);
if (ret)
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 7fff145..3b93209 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -56,6 +56,8 @@
int resuming; /* starting a resumed session */
int reauth; /* reauthentication */
u8 *key_data;
+ u8 *session_id;
+ size_t id_len;
struct wpabuf *pending_phase2_req;
enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
@@ -179,6 +181,7 @@
os_free(data->phase2_types);
eap_peer_tls_ssl_deinit(sm, &data->ssl);
os_free(data->key_data);
+ os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
os_free(data);
}
@@ -1107,6 +1110,20 @@
"derive key");
}
+ os_free(data->session_id);
+ data->session_id =
+ eap_peer_tls_derive_session_id(sm, &data->ssl,
+ EAP_TYPE_PEAP,
+ &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-PEAP: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to "
+ "derive Session-Id");
+ }
+
if (sm->workaround && data->resuming) {
/*
* At least few RADIUS servers (Aegis v1.1.6;
@@ -1178,6 +1195,8 @@
struct eap_peap_data *data = priv;
os_free(data->key_data);
data->key_data = NULL;
+ os_free(data->session_id);
+ data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data);
return NULL;
@@ -1260,6 +1279,25 @@
}
+static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+ u8 *id;
+
+ if (data->session_id == NULL || !data->phase2_success)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
int eap_peer_peap_register(void)
{
struct eap_method *eap;
@@ -1279,6 +1317,7 @@
eap->has_reauth_data = eap_peap_has_reauth_data;
eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
eap->init_for_reauth = eap_peap_init_for_reauth;
+ eap->getSessionId = eap_peap_get_session_id;
ret = eap_peer_method_register(eap);
if (ret)
diff --git a/src/eap_peer/eap_proxy.h b/src/eap_peer/eap_proxy.h
new file mode 100644
index 0000000..3b4dcef
--- /dev/null
+++ b/src/eap_peer/eap_proxy.h
@@ -0,0 +1,48 @@
+/*
+ * EAP proxy definitions
+ * Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_PROXY_H
+#define EAP_PROXY_H
+
+struct eap_proxy_sm;
+struct eapol_callbacks;
+struct eap_sm;
+struct eap_peer_config;
+
+enum eap_proxy_status {
+ EAP_PROXY_FAILURE = 0x00,
+ EAP_PROXY_SUCCESS
+};
+
+struct eap_proxy_sm *
+eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ void *msg_ctx);
+
+void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy);
+
+int eap_proxy_key_available(struct eap_proxy_sm *sm);
+
+const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len);
+
+struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *sm);
+
+int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm);
+
+enum eap_proxy_status
+eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData,
+ int eapReqDataLen);
+
+int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
+ int verbose);
+
+int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len);
+
+int eap_proxy_notify_config(struct eap_proxy_sm *sm,
+ struct eap_peer_config *config);
+
+#endif /* EAP_PROXY_H */
diff --git a/src/eap_peer/eap_proxy_dummy.c b/src/eap_peer/eap_proxy_dummy.c
new file mode 100644
index 0000000..cd97fb6
--- /dev/null
+++ b/src/eap_peer/eap_proxy_dummy.c
@@ -0,0 +1,76 @@
+/*
+ * EAP proxy - dummy implementation for build testing
+ * Copyright (c) 2013 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 "eap_proxy.h"
+
+struct eap_proxy_sm *
+eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ void *msg_ctx)
+{
+ return NULL;
+}
+
+
+void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy)
+{
+}
+
+
+int eap_proxy_key_available(struct eap_proxy_sm *sm)
+{
+ return 0;
+}
+
+
+const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len)
+{
+ return NULL;
+}
+
+
+struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *sm)
+{
+ return NULL;
+}
+
+
+int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm)
+{
+ return 0;
+}
+
+
+enum eap_proxy_status
+eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData,
+ int eapReqDataLen)
+{
+ return EAP_PROXY_FAILURE;
+}
+
+
+int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
+ int verbose)
+{
+ return 0;
+}
+
+
+int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len)
+{
+ return -1;
+}
+
+
+int eap_proxy_notify_config(struct eap_proxy_sm *sm,
+ struct eap_peer_config *config)
+{
+ return -1;
+}
diff --git a/src/eap_peer/eap_psk.c b/src/eap_peer/eap_psk.c
index d618fcf..cd0e3f9 100644
--- a/src/eap_peer/eap_psk.c
+++ b/src/eap_peer/eap_psk.c
@@ -21,6 +21,7 @@
struct eap_psk_data {
enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
u8 rand_p[EAP_PSK_RAND_LEN];
+ u8 rand_s[EAP_PSK_RAND_LEN];
u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
u8 *id_s, *id_p;
size_t id_s_len, id_p_len;
@@ -112,6 +113,7 @@
}
wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
EAP_PSK_RAND_LEN);
+ os_memcpy(data->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
os_free(data->id_s);
data->id_s_len = len - sizeof(*hdr1);
data->id_s = os_malloc(data->id_s_len);
@@ -434,6 +436,28 @@
}
+static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_psk_data *data = priv;
+ u8 *id;
+
+ if (data->state != PSK_DONE)
+ return NULL;
+
+ *len = 1 + 2 * EAP_PSK_RAND_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_PSK;
+ os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_psk_data *data = priv;
@@ -468,6 +492,7 @@
eap->process = eap_psk_process;
eap->isKeyAvailable = eap_psk_isKeyAvailable;
eap->getKey = eap_psk_getKey;
+ eap->getSessionId = eap_psk_get_session_id;
eap->get_emsk = eap_psk_get_emsk;
ret = eap_peer_method_register(eap);
diff --git a/src/eap_peer/eap_sake.c b/src/eap_peer/eap_sake.c
index e072f46..431519c 100644
--- a/src/eap_peer/eap_sake.c
+++ b/src/eap_peer/eap_sake.c
@@ -452,6 +452,28 @@
}
+static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sake_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + 2 * EAP_SAKE_RAND_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_SAKE;
+ os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
+ os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_sake_data *data = priv;
@@ -485,6 +507,7 @@
eap->process = eap_sake_process;
eap->isKeyAvailable = eap_sake_isKeyAvailable;
eap->getKey = eap_sake_getKey;
+ eap->getSessionId = eap_sake_get_session_id;
eap->get_emsk = eap_sake_get_emsk;
ret = eap_peer_method_register(eap);
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index c936a44..82ea18d 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -1084,6 +1084,29 @@
}
+static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sim_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_SIM;
+ os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
+ os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
+ EAP_SIM_NONCE_MT_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_sim_data *data = priv;
@@ -1118,6 +1141,7 @@
eap->process = eap_sim_process;
eap->isKeyAvailable = eap_sim_isKeyAvailable;
eap->getKey = eap_sim_getKey;
+ eap->getSessionId = eap_sim_get_session_id;
eap->has_reauth_data = eap_sim_has_reauth_data;
eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
eap->init_for_reauth = eap_sim_init_for_reauth;
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index 061a72b..d2066cd 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -21,6 +21,8 @@
struct eap_tls_data {
struct eap_ssl_data ssl;
u8 *key_data;
+ u8 *session_id;
+ size_t id_len;
void *ssl_ctx;
u8 eap_type;
};
@@ -103,6 +105,7 @@
return;
eap_peer_tls_ssl_deinit(sm, &data->ssl);
os_free(data->key_data);
+ os_free(data->session_id);
os_free(data);
}
@@ -165,6 +168,17 @@
} else {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
}
+
+ os_free(data->session_id);
+ data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
+ EAP_TYPE_TLS,
+ &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id");
+ }
}
@@ -228,6 +242,8 @@
struct eap_tls_data *data = priv;
os_free(data->key_data);
data->key_data = NULL;
+ os_free(data->session_id);
+ data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data);
return NULL;
@@ -289,6 +305,25 @@
}
+static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_tls_data *data = priv;
+ u8 *id;
+
+ if (data->session_id == NULL)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
int eap_peer_tls_register(void)
{
struct eap_method *eap;
@@ -304,6 +339,7 @@
eap->process = eap_tls_process;
eap->isKeyAvailable = eap_tls_isKeyAvailable;
eap->getKey = eap_tls_getKey;
+ eap->getSessionId = eap_tls_get_session_id;
eap->get_status = eap_tls_get_status;
eap->has_reauth_data = eap_tls_has_reauth_data;
eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index aedd85a..a777bb0 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -340,6 +340,52 @@
/**
+ * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ * @len: Pointer to length of the session ID generated
+ * Returns: Pointer to allocated Session-Id on success or %NULL on failure
+ *
+ * This function derive the Session-Id based on the TLS session data
+ * (client/server random and method type).
+ *
+ * The caller is responsible for freeing the returned buffer.
+ */
+u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len)
+{
+ struct tls_keys keys;
+ u8 *out;
+
+ /*
+ * TLS library did not support session ID generation,
+ * so get the needed TLS session parameters
+ */
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ return NULL;
+
+ if (keys.client_random == NULL || keys.server_random == NULL ||
+ keys.master_key == NULL)
+ return NULL;
+
+ *len = 1 + keys.client_random_len + keys.server_random_len;
+ out = os_malloc(*len);
+ if (out == NULL)
+ return NULL;
+
+ /* Session-Id = EAP type || client.random || server.random */
+ out[0] = eap_type;
+ os_memcpy(out + 1, keys.client_random, keys.client_random_len);
+ os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
+ keys.server_random_len);
+
+ return out;
+}
+
+
+/**
* eap_peer_tls_reassemble_fragment - Reassemble a received fragment
* @data: Data for TLS processing
* @in_data: Next incoming TLS segment
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index 91d3a25..1a5e0f8 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -94,6 +94,9 @@
void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
const char *label, size_t len);
+u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len);
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
EapType eap_type, int peap_version,
u8 id, const u8 *in_data, size_t in_len,
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 9360a42..5091bf0 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -54,6 +54,8 @@
int resuming; /* starting a resumed session */
int reauth; /* reauthentication */
u8 *key_data;
+ u8 *session_id;
+ size_t id_len;
struct wpabuf *pending_phase2_req;
@@ -140,6 +142,7 @@
os_free(data->phase2_eap_types);
eap_peer_tls_ssl_deinit(sm, &data->ssl);
os_free(data->key_data);
+ os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
os_free(data);
}
@@ -222,6 +225,17 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
data->key_data, EAP_TLS_KEY_LEN);
+ os_free(data->session_id);
+ data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
+ EAP_TYPE_TTLS,
+ &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id");
+ }
+
return 0;
}
@@ -1528,6 +1542,8 @@
struct eap_ttls_data *data = priv;
os_free(data->key_data);
data->key_data = NULL;
+ os_free(data->session_id);
+ data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data);
return NULL;
@@ -1612,6 +1628,25 @@
}
+static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+ u8 *id;
+
+ if (data->session_id == NULL || !data->phase2_success)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
int eap_peer_ttls_register(void)
{
struct eap_method *eap;
@@ -1627,6 +1662,7 @@
eap->process = eap_ttls_process;
eap->isKeyAvailable = eap_ttls_isKeyAvailable;
eap->getKey = eap_ttls_getKey;
+ eap->getSessionId = eap_ttls_get_session_id;
eap->get_status = eap_ttls_get_status;
eap->has_reauth_data = eap_ttls_has_reauth_data;
eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index d007a57..f358156 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -194,7 +194,8 @@
cfg.pin = dev_pw;
cfg.pin_len /= 2;
}
- if (cfg.pin_len == 6 && os_strncmp(pos, "nfc-pw", 6) == 0) {
+ if (cfg.pin_len == 6 &&
+ os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) {
cfg.pin = NULL;
cfg.pin_len = 0;
nfc = 1;
diff --git a/src/eap_server/ikev2.c b/src/eap_server/ikev2.c
index 0e77efb..512ba30 100644
--- a/src/eap_server/ikev2.c
+++ b/src/eap_server/ikev2.c
@@ -990,7 +990,7 @@
*/
wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv));
wpabuf_put_buf(msg, pv);
- os_free(pv);
+ wpabuf_free(pv);
plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
WPA_PUT_BE16(phdr->payload_length, plen);
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index f90fb62..2e56086 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -16,6 +16,7 @@
#include "crypto/md5.h"
#include "common/eapol_common.h"
#include "eap_peer/eap.h"
+#include "eap_peer/eap_proxy.h"
#include "eapol_supp_sm.h"
#define STATE_MACHINE_DATA struct eapol_sm
@@ -136,6 +137,10 @@
Boolean cached_pmk;
Boolean unicast_key_received, broadcast_key_received;
+#ifdef CONFIG_EAP_PROXY
+ Boolean use_eap_proxy;
+ struct eap_proxy_sm *eap_proxy;
+#endif /* CONFIG_EAP_PROXY */
};
@@ -463,6 +468,17 @@
sm->keyRun = TRUE;
sm->suppSuccess = TRUE;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ if (eap_proxy_key_available(sm->eap_proxy)) {
+ /* New key received - clear IEEE 802.1X EAPOL-Key replay
+ * counter */
+ sm->replay_counter_valid = FALSE;
+ }
+ return;
+ }
+#endif /* CONFIG_EAP_PROXY */
+
if (eap_key_available(sm->eap)) {
/* New key received - clear IEEE 802.1X EAPOL-Key replay
* counter */
@@ -806,6 +822,19 @@
struct wpabuf *resp;
wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
+
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Get EAP Response from EAP Proxy */
+ resp = eap_proxy_get_eapRespData(sm->eap_proxy);
+ if (resp == NULL) {
+ wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
+ "response data not available");
+ return;
+ }
+ } else
+#endif /* CONFIG_EAP_PROXY */
+
resp = eap_get_eapRespData(sm->eap);
if (resp == NULL) {
wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
@@ -883,6 +912,13 @@
SM_STEP_RUN(SUPP_PAE);
SM_STEP_RUN(KEY_RX);
SM_STEP_RUN(SUPP_BE);
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Drive the EAP proxy state machine */
+ if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
+ sm->changed = TRUE;
+ } else
+#endif /* CONFIG_EAP_PROXY */
if (eap_peer_sm_step(sm->eap))
sm->changed = TRUE;
if (!sm->changed)
@@ -1070,6 +1106,13 @@
len += ret;
}
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy)
+ len += eap_proxy_sm_get_status(sm->eap_proxy,
+ buf + len, buflen - len,
+ verbose);
+ else
+#endif /* CONFIG_EAP_PROXY */
len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
return len;
@@ -1227,6 +1270,16 @@
wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
"frame");
sm->eapolEap = TRUE;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ eap_proxy_packet_update(
+ sm->eap_proxy,
+ wpabuf_mhead_u8(sm->eapReqData),
+ wpabuf_len(sm->eapReqData));
+ wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
+ "EAP Req updated");
+ }
+#endif /* CONFIG_EAP_PROXY */
eapol_sm_step(sm);
}
break;
@@ -1387,6 +1440,9 @@
return;
sm->config = config;
+#ifdef CONFIG_EAP_PROXY
+ sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
+#endif /* CONFIG_EAP_PROXY */
if (conf == NULL)
return;
@@ -1395,6 +1451,12 @@
sm->conf.required_keys = conf->required_keys;
sm->conf.fast_reauth = conf->fast_reauth;
sm->conf.workaround = conf->workaround;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Using EAP Proxy, so skip EAP state machine update */
+ return;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (sm->eap) {
eap_set_fast_reauth(sm->eap, conf->fast_reauth);
eap_set_workaround(sm->eap, conf->workaround);
@@ -1419,6 +1481,22 @@
const u8 *eap_key;
size_t eap_len;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Get key from EAP proxy */
+ if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
+ wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
+ return -1;
+ }
+ eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
+ if (eap_key == NULL) {
+ wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
+ "eapKeyData");
+ return -1;
+ }
+ goto key_fetched;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (sm == NULL || !eap_key_available(sm->eap)) {
wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
return -1;
@@ -1428,6 +1506,9 @@
wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
return -1;
}
+#ifdef CONFIG_EAP_PROXY
+key_fetched:
+#endif /* CONFIG_EAP_PROXY */
if (len > eap_len) {
wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
"available (len=%lu)",
@@ -1889,6 +1970,14 @@
return NULL;
}
+#ifdef CONFIG_EAP_PROXY
+ sm->use_eap_proxy = FALSE;
+ sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
+ if (sm->eap_proxy == NULL) {
+ wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
+ }
+#endif /* CONFIG_EAP_PROXY */
+
/* Initialize EAPOL state machines */
sm->initialize = TRUE;
eapol_sm_step(sm);
@@ -1915,6 +2004,9 @@
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
eap_peer_sm_deinit(sm->eap);
+#ifdef CONFIG_EAP_PROXY
+ eap_proxy_deinit(sm->eap_proxy);
+#endif /* CONFIG_EAP_PROXY */
os_free(sm->last_rx_key);
wpabuf_free(sm->eapReqData);
os_free(sm->ctx);
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index aaacc9a..985227c 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -617,8 +617,18 @@
}
if (!probe_req) {
- dev->info.config_methods = msg->config_methods ?
+ u16 new_config_methods;
+ new_config_methods = msg->config_methods ?
msg->config_methods : msg->wps_config_methods;
+ if (new_config_methods &&
+ dev->info.config_methods != new_config_methods) {
+ wpa_printf(MSG_DEBUG, "P2P: Update peer " MACSTR
+ " config_methods 0x%x -> 0x%x",
+ MAC2STR(dev->info.p2p_device_addr),
+ dev->info.config_methods,
+ new_config_methods);
+ dev->info.config_methods = new_config_methods;
+ }
}
}
@@ -630,7 +640,7 @@
* P2P Device Address or P2P Interface Address)
* @level: Signal level (signal strength of the received frame from the peer)
* @freq: Frequency on which the Beacon or Probe Response frame was received
- * @age_ms: Age of the information in milliseconds
+ * @rx_time: Time when the result 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
@@ -642,14 +652,14 @@
* Info attributes.
*/
int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
- unsigned int age_ms, int level, const u8 *ies,
+ struct os_time *rx_time, int level, const u8 *ies,
size_t ies_len, int scan_res)
{
struct p2p_device *dev;
struct p2p_message msg;
const u8 *p2p_dev_addr;
int i;
- struct os_time time_now, time_tmp_age, entry_ts;
+ struct os_time time_now;
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ies, ies_len, &msg)) {
@@ -686,22 +696,29 @@
return -1;
}
- os_get_time(&time_now);
- time_tmp_age.sec = age_ms / 1000;
- time_tmp_age.usec = (age_ms % 1000) * 1000;
- os_time_sub(&time_now, &time_tmp_age, &entry_ts);
+ if (rx_time == NULL) {
+ os_get_time(&time_now);
+ rx_time = &time_now;
+ }
/*
* Update the device entry only if the new peer
* entry is newer than the one previously stored.
*/
- if (dev->last_seen.usec > 0 &&
- os_time_before(&entry_ts, &dev->last_seen)) {
+ if (dev->last_seen.sec > 0 &&
+ os_time_before(rx_time, &dev->last_seen)) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not update peer "
+ "entry based on old frame (rx_time=%u.%06u "
+ "last_seen=%u.%06u)",
+ (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec,
+ (unsigned int) dev->last_seen.sec,
+ (unsigned int) dev->last_seen.usec);
p2p_parse_free(&msg);
return -1;
}
- os_memcpy(&dev->last_seen, &entry_ts, sizeof(struct os_time));
+ os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_time));
dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
@@ -780,13 +797,37 @@
return 0;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer found with Listen frequency %d MHz", freq);
+ "P2P: Peer found with Listen frequency %d MHz "
+ "(rx_time=%u.%06u)", freq, (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec);
if (dev->flags & P2P_DEV_USER_REJECTED) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Do not report rejected device");
return 0;
}
+ if (dev->info.config_methods == 0 &&
+ (freq == 2412 || freq == 2437 || freq == 2462)) {
+ /*
+ * If we have only seen a Beacon frame from a GO, we do not yet
+ * know what WPS config methods it supports. Since some
+ * applications use config_methods value from P2P-DEVICE-FOUND
+ * events, postpone reporting this peer until we've fully
+ * discovered its capabilities.
+ *
+ * At least for now, do this only if the peer was detected on
+ * one of the social channels since that peer can be easily be
+ * found again and there are no limitations of having to use
+ * passive scan on this channels, so this can be done through
+ * Probe Response frame that includes the config_methods
+ * information.
+ */
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Do not report peer " MACSTR " with unknown "
+ "config methods", MAC2STR(addr));
+ return 0;
+ }
+
p2p->cfg->dev_found(p2p->cfg->cb_ctx, addr, &dev->info,
!(dev->flags & P2P_DEV_REPORTED_ONCE));
dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
@@ -1031,6 +1072,7 @@
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting find (type=%d)",
type);
+ os_get_time(&p2p->find_start);
if (p2p->p2p_scan_running) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan is "
"already running");
@@ -1133,8 +1175,10 @@
"now that previous scan was completed");
if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
p2p->num_req_dev_types, p2p->req_dev_types,
- p2p->find_dev_id, p2p->search_delay) < 0)
+ p2p->find_dev_id, p2p->search_delay) < 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
return 0;
+ }
return 1;
}
@@ -2887,10 +2931,25 @@
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
- unsigned int age, int level, const u8 *ies,
+ struct os_time *rx_time, int level, const u8 *ies,
size_t ies_len)
{
- p2p_add_device(p2p, bssid, freq, age, level, ies, ies_len, 1);
+ if (os_time_before(rx_time, &p2p->find_start)) {
+ /*
+ * The driver may have cached (e.g., in cfg80211 BSS table) the
+ * scan results for relatively long time. To avoid reporting
+ * stale information, update P2P peers only based on results
+ * that have based on frames received after the last p2p_find
+ * operation was started.
+ */
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore old scan "
+ "result for " MACSTR " (rx_time=%u.%06u)",
+ MAC2STR(bssid), (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec);
+ return 0;
+ }
+
+ p2p_add_device(p2p, bssid, freq, rx_time, level, ies, ies_len, 1);
return 0;
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 18e733b..0663fbb 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1200,7 +1200,7 @@
* @p2p: P2P module context from p2p_init()
* @bssid: BSSID of the scan result
* @freq: Frequency of the channel on which the device was found in MHz
- * @age: Age of the scan result in milliseconds
+ * @rx_time: Time when the result was received
* @level: Signal level (signal strength of the received Beacon/Probe Response
* frame)
* @ies: Pointer to IEs from the scan result
@@ -1222,7 +1222,7 @@
* start of a pending operation, e.g., to start a pending GO negotiation.
*/
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
- unsigned int age, int level, const u8 *ies,
+ struct os_time *rx_time, int level, const u8 *ies,
size_t ies_len);
/**
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 712544b..b2a3d3f 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -403,6 +403,8 @@
u8 *find_dev_id;
u8 find_dev_id_buf[ETH_ALEN];
+ struct os_time find_start; /* time of last p2p_find start */
+
struct p2p_group **groups;
size_t num_groups;
@@ -706,7 +708,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,
- unsigned int age_ms, int level, const u8 *ies,
+ struct os_time *rx_time, int level, const u8 *ies,
size_t ies_len, int scan_res);
struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index ac67932..9283113 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -176,7 +176,7 @@
"P2P: Invitation Request from unknown peer "
MACSTR, MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, 0, data + 1, len - 1,
+ if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
0)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Invitation Request add device failed "
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index ca33f17..44db682 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -152,7 +152,7 @@
"P2P: Provision Discovery Request from "
"unknown peer " MACSTR, MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, 0, data + 1, len - 1,
+ if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
0)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Provision Discovery Request add device "
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 9a79d28..09adc19 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -120,6 +120,13 @@
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
size_t supp_rates_len;
+
+ struct ieee80211_ht_capabilities *ht_capabilities;
+
+ u8 qos_info;
+
+ u8 *ext_capab;
+ size_t ext_capab_len;
};
@@ -611,6 +618,10 @@
peer->initiator = 0;
os_free(peer->sm_tmr.buf);
peer->sm_tmr.buf = NULL;
+ os_free(peer->ht_capabilities);
+ peer->ht_capabilities = NULL;
+ os_free(peer->ext_capab);
+ peer->ext_capab = NULL;
peer->rsnie_i_len = peer->rsnie_p_len = 0;
peer->cipher = 0;
peer->tpk_set = peer->tpk_success = 0;
@@ -681,8 +692,10 @@
pos = rbuf;
if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) {
- /* Overwrite the reason code */
- reason_code = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
+ if (reason_code != WLAN_REASON_DEAUTH_LEAVING) {
+ /* Overwrite the reason code */
+ reason_code = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
+ }
goto skip_ies;
}
@@ -1329,6 +1342,58 @@
}
+static int copy_peer_ht_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->ht_capabilities ||
+ kde->ht_capabilities_len <
+ sizeof(struct ieee80211_ht_capabilities) ) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported ht capabilities "
+ "received");
+ return 0;
+ }
+
+ if (!peer->ht_capabilities) {
+ peer->ht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_ht_capabilities));
+ if (peer->ht_capabilities == NULL)
+ return -1;
+ }
+
+ os_memcpy(peer->ht_capabilities, kde->ht_capabilities,
+ sizeof(struct ieee80211_ht_capabilities));
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer HT capabilities",
+ (u8 *) peer->ht_capabilities,
+ sizeof(struct ieee80211_ht_capabilities));
+
+ return 0;
+}
+
+
+static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->ext_capab) {
+ wpa_printf(MSG_DEBUG, "TDLS: No extended capabilities "
+ "received");
+ return 0;
+ }
+
+ if (!peer->ext_capab || peer->ext_capab_len < kde->ext_capab_len - 2) {
+ /* Need to allocate buffer to fit the new information */
+ os_free(peer->ext_capab);
+ peer->ext_capab = os_zalloc(kde->ext_capab_len - 2);
+ if (peer->ext_capab == NULL)
+ return -1;
+ }
+
+ peer->ext_capab_len = kde->ext_capab_len - 2;
+ os_memcpy(peer->ext_capab, kde->ext_capab + 2, peer->ext_capab_len);
+
+ return 0;
+}
+
+
static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -1398,6 +1463,14 @@
if (copy_supp_rates(&kde, peer) < 0)
goto error;
+ if (copy_peer_ht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_ext_capab(&kde, peer) < 0)
+ goto error;
+
+ peer->qos_info = kde.qosinfo;
+
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
peer = wpa_tdls_add_peer(sm, src_addr, NULL);
@@ -1621,7 +1694,8 @@
skip_rsn_check:
/* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0, NULL, 0,
+ NULL, 0);
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
@@ -1661,9 +1735,11 @@
#endif /* CONFIG_TDLS_TESTING */
}
- /* add supported rates and capabilities to the TDLS peer */
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
- peer->supp_rates, peer->supp_rates_len);
+ peer->supp_rates, peer->supp_rates_len,
+ peer->ht_capabilities, peer->qos_info,
+ peer->ext_capab, peer->ext_capab_len);
wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
}
@@ -1759,6 +1835,14 @@
if (copy_supp_rates(&kde, peer) < 0)
goto error;
+ if (copy_peer_ht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_ext_capab(&kde, peer) < 0)
+ goto error;
+
+ peer->qos_info = kde.qosinfo;
+
if (!wpa_tdls_get_privacy(sm)) {
peer->rsnie_p_len = 0;
peer->cipher = WPA_CIPHER_NONE;
@@ -2062,7 +2146,8 @@
peer->initiator = 1;
/* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0, NULL, 0,
+ NULL, 0);
if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
wpa_tdls_disable_link(sm, peer->addr);
@@ -2207,6 +2292,28 @@
}
+void wpa_tdls_teardown_peers(struct wpa_sm *sm)
+{
+ struct wpa_tdls_peer *peer;
+
+ peer = sm->tdls;
+
+ wpa_printf(MSG_DEBUG, "TDLS: Tear down peers");
+
+ while (peer) {
+ wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR,
+ MAC2STR(peer->addr));
+ if (sm->tdls_external_setup)
+ wpa_tdls_send_teardown(sm, peer->addr,
+ WLAN_REASON_DEAUTH_LEAVING);
+ else
+ wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+
+ peer = peer->next;
+ }
+}
+
+
static void wpa_tdls_remove_peers(struct wpa_sm *sm)
{
struct wpa_tdls_peer *peer, *tmp;
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 2c989b7..6679dda 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -12,6 +12,7 @@
#include "common/defs.h"
#include "common/eapol_common.h"
#include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
struct wpa_sm;
struct eapol_sm;
@@ -57,7 +58,10 @@
int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
u16 capability, const u8 *supp_rates,
- size_t supp_rates_len);
+ size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ u8 qosinfo, const u8 *ext_capab,
+ size_t ext_capab_len);
#endif /* CONFIG_TDLS */
void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
const u8 *replay_ctr);
@@ -360,6 +364,7 @@
int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_init(struct wpa_sm *sm);
+void wpa_tdls_teardown_peers(struct wpa_sm *sm);
void wpa_tdls_deinit(struct wpa_sm *sm);
void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 9f9e641..5dae5de 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -283,12 +283,16 @@
static inline int
wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
u16 capability, const u8 *supp_rates,
- size_t supp_rates_len)
+ size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len)
{
if (sm->ctx->tdls_peer_addset)
return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
capability, supp_rates,
- supp_rates_len);
+ supp_rates_len, ht_capab,
+ qosinfo, ext_capab,
+ ext_capab_len);
return -1;
}
#endif /* CONFIG_TDLS */
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 3d75365..252737f 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -427,6 +427,11 @@
} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
ie->ext_supp_rates = pos;
ie->ext_supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_HT_CAP) {
+ ie->ht_capabilities = pos + 2;
+ ie->ht_capabilities_len = pos[1];
+ } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+ ie->qosinfo = pos[2];
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
ret = wpa_parse_generic(pos, end, ie);
if (ret < 0)
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 5afdfe9..b212711 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -49,6 +49,9 @@
size_t supp_rates_len;
const u8 *ext_supp_rates;
size_t ext_supp_rates_len;
+ const u8 *ht_capabilities;
+ size_t ht_capabilities_len;
+ u8 qosinfo;
};
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 23a93be..cc22e83 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -257,7 +257,11 @@
* We ignore errors here since errors are normal if we
* are already running as non-root.
*/
+#ifdef ANDROID_SETGROUPS_OVERRIDE
+ gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
+#else /* ANDROID_SETGROUPS_OVERRIDE */
gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
+#endif /* ANDROID_SETGROUPS_OVERRIDE */
struct __user_cap_header_struct header;
struct __user_cap_data_struct cap;
diff --git a/src/wps/ndef.c b/src/wps/ndef.c
index a48a2d7..96685d2 100644
--- a/src/wps/ndef.c
+++ b/src/wps/ndef.c
@@ -170,10 +170,30 @@
}
+struct wpabuf * ndef_build_wifi_hc(int begin)
+{
+ struct wpabuf *hc, *carrier;
+
+ carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
+ if (carrier == NULL)
+ return NULL;
+ wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */
+ wpabuf_put_u8(carrier, os_strlen(wifi_handover_type));
+ wpabuf_put_str(carrier, wifi_handover_type);
+
+ hc = ndef_build_record((begin ? FLAG_MESSAGE_BEGIN : 0) |
+ FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
+ "0", 1, carrier);
+ wpabuf_free(carrier);
+
+ return hc;
+}
+
+
struct wpabuf * ndef_build_wifi_hr(void)
{
struct wpabuf *rn, *cr, *ac_payload, *ac, *hr_payload, *hr;
- struct wpabuf *carrier, *hc;
+ struct wpabuf *hc;
rn = wpabuf_alloc(2);
if (rn == NULL)
@@ -224,18 +244,7 @@
if (hr == NULL)
return NULL;
- carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
- if (carrier == NULL) {
- wpabuf_free(hr);
- return NULL;
- }
- wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */
- wpabuf_put_u8(carrier, os_strlen(wifi_handover_type));
- wpabuf_put_str(carrier, wifi_handover_type);
-
- hc = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
- "0", 1, carrier);
- wpabuf_free(carrier);
+ hc = ndef_build_wifi_hc(0);
if (hc == NULL) {
wpabuf_free(hr);
return NULL;
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 2575705..ff4b20d 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -53,12 +53,18 @@
}
os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
data->dev_password_len = cfg->pin_len;
+ wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password",
+ data->dev_password, data->dev_password_len);
}
#ifdef CONFIG_WPS_NFC
if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
+ /* Keep AP PIN as alternative Device Password */
+ data->alt_dev_pw_id = data->dev_pw_id;
+ data->alt_dev_password = data->dev_password;
+ data->alt_dev_password_len = data->dev_password_len;
+
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) {
@@ -69,6 +75,8 @@
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);
+ wpa_hexdump_key(MSG_DEBUG, "WPS: NFC dev_password",
+ data->dev_password, data->dev_password_len);
}
#endif /* CONFIG_WPS_NFC */
@@ -155,6 +163,7 @@
wpabuf_free(data->dh_pubkey_r);
wpabuf_free(data->last_msg);
os_free(data->dev_password);
+ os_free(data->alt_dev_password);
os_free(data->new_psk);
wps_device_data_free(&data->peer_dev);
os_free(data->new_ap_settings);
diff --git a/src/wps/wps.h b/src/wps/wps.h
index c6b7099..39fce56 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -810,6 +810,8 @@
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_build(int ndef, int id, struct wpabuf *pubkey,
+ struct wpabuf *dev_pw);
struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
struct wpabuf **privkey,
struct wpabuf **dev_pw);
@@ -817,6 +819,7 @@
/* ndef.c */
struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
+struct wpabuf * ndef_build_wifi_hc(int begin);
struct wpabuf * ndef_build_wifi_hr(void);
#ifdef CONFIG_WPS_STRICT
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 68d9f0a..0897b7b 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -562,11 +562,34 @@
#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
+ struct wpabuf *dev_pw)
+{
+ struct wpabuf *ret;
+
+ if (pubkey == NULL || dev_pw == NULL)
+ return NULL;
+
+ 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;
+}
+
+
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;
+ struct wpabuf *priv = NULL, *pub = NULL, *pw;
void *dh_ctx;
u16 val;
@@ -596,16 +619,7 @@
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;
+ return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
}
+
#endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 837b941..9c0cebb 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -837,6 +837,39 @@
}
+static int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id)
+{
+ u16 id;
+
+ if (dev_pw_id == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Device Password ID");
+ return -1;
+ }
+
+ id = WPA_GET_BE16(dev_pw_id);
+ if (wps->dev_pw_id == id) {
+ wpa_printf(MSG_DEBUG, "WPS: Device Password ID %u", id);
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
+ "ID from %u to %u", wps->dev_pw_id, id);
+
+ if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
+ wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
+ os_free(wps->dev_password);
+ wps->dev_pw_id = wps->alt_dev_pw_id;
+ wps->dev_password = wps->alt_dev_password;
+ wps->dev_password_len = wps->alt_dev_password_len;
+ wps->alt_dev_password = NULL;
+ wps->alt_dev_password_len = 0;
+ return 0;
+ }
+
+ return -1;
+}
+
+
static enum wps_process_res wps_process_m2(struct wps_data *wps,
const struct wpabuf *msg,
struct wps_parse_attr *attr)
@@ -852,7 +885,8 @@
if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
- wps_process_uuid_r(wps, attr->uuid_r)) {
+ wps_process_uuid_r(wps, attr->uuid_r) ||
+ wps_process_dev_pw_id(wps, attr->dev_password_id)) {
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index 8110894..6efc3bf 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -71,6 +71,9 @@
size_t dev_password_len;
u16 dev_pw_id;
int pbc;
+ u8 *alt_dev_password;
+ size_t alt_dev_password_len;
+ u16 alt_dev_pw_id;
/**
* request_type - Request Type attribute from (Re)AssocReq
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 11e7e84..f01e3b3 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -1363,6 +1363,14 @@
} else {
pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
&pin_len);
+ if (pin && wps->dev_pw_id >= 0x10) {
+ wpa_printf(MSG_DEBUG, "WPS: No match for OOB Device "
+ "Password ID, but PIN found");
+ /*
+ * See whether Enrollee is willing to use PIN instead.
+ */
+ wps->dev_pw_id = DEV_PW_DEFAULT;
+ }
}
if (pin == NULL) {
wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 7545ab2..4332d82 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -504,6 +504,13 @@
NEED_AES_CBC=y
endif
+ifdef CONFIG_EAP_PROXY
+L_CFLAGS += -DCONFIG_EAP_PROXY
+OBJS += src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).c
+include eap_proxy_$(CONFIG_EAP_PROXY).mk
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_EAP_AKA_PRIME
# EAP-AKA'
ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index f39a3d7..da2abfc 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -482,6 +482,13 @@
NEED_AES_CBC=y
endif
+ifdef CONFIG_EAP_PROXY
+CFLAGS += -DCONFIG_EAP_PROXY
+OBJS += ../src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).o
+include eap_proxy_$(CONFIG_EAP_PROXY).mk
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_EAP_AKA_PRIME
# EAP-AKA'
ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index 1ea9843..2a1dda5 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -336,6 +336,16 @@
tokens during manufacturing (each station needs to have its own random
keys).
+The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
+NFC configuration token when wpa_supplicant is controlling an AP
+interface (AP or P2P GO). 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.
+
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
@@ -375,3 +385,10 @@
of NFC connection handover select. The payload may include multiple
carriers the the applicable ones are matched based on the media
type.
+
+"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
+<carrier from handover select>" can be used as an alternative way for
+reporting completed NFC connection handover. The first parameter
+indicates whether the local device initiated or responded to the
+connection handover and the carrier records are the selected carrier
+from the handover request and select messages as a hexdump.
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 85ee6cb..82b7e19 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -848,6 +848,34 @@
hapd->conf->ap_pin = NULL;
}
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hostapd_wps_nfc_config_token(hapd, ndef);
+}
+
+
+struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hostapd_wps_nfc_hs_cr(hapd, ndef);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
#endif /* CONFIG_WPS */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 536064f..fd4c25a 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -52,5 +52,9 @@
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);
+struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef);
+struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef);
#endif /* AP_H */
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 87b7db8..c50de53 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -224,7 +224,8 @@
}
-static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
+static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
+ struct os_time *fetch_time)
{
os_time_t usec;
@@ -238,7 +239,8 @@
dst->level = src->level;
dst->tsf = src->tsf;
- os_get_time(&dst->last_update);
+ dst->last_update.sec = fetch_time->sec;
+ dst->last_update.usec = fetch_time->usec;
dst->last_update.sec -= src->age / 1000;
usec = (src->age % 1000) * 1000;
if (dst->last_update.usec < usec) {
@@ -315,7 +317,8 @@
static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
const u8 *ssid, size_t ssid_len,
- struct wpa_scan_res *res)
+ struct wpa_scan_res *res,
+ struct os_time *fetch_time)
{
struct wpa_bss *bss;
@@ -324,7 +327,7 @@
return NULL;
bss->id = wpa_s->bss_next_id++;
bss->last_update_idx = wpa_s->bss_update_idx;
- wpa_bss_copy_res(bss, res);
+ wpa_bss_copy_res(bss, res, fetch_time);
os_memcpy(bss->ssid, ssid, ssid_len);
bss->ssid_len = ssid_len;
bss->ie_len = res->ie_len;
@@ -480,14 +483,14 @@
static struct wpa_bss *
wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- struct wpa_scan_res *res)
+ struct wpa_scan_res *res, struct os_time *fetch_time)
{
u32 changes;
changes = wpa_bss_compare_res(bss, res);
bss->scan_miss_count = 0;
bss->last_update_idx = wpa_s->bss_update_idx;
- wpa_bss_copy_res(bss, res);
+ wpa_bss_copy_res(bss, res, fetch_time);
/* Move the entry to the end of the list */
dl_list_del(&bss->list);
if (bss->ie_len + bss->beacon_ie_len >=
@@ -551,13 +554,15 @@
* wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
* @wpa_s: Pointer to wpa_supplicant data
* @res: Scan result
+ * @fetch_time: Time when the result was fetched from the driver
*
* This function updates a BSS table entry (or adds one) based on a scan result.
* This is called separately for each scan result between the calls to
* wpa_bss_update_start() and wpa_bss_update_end().
*/
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res)
+ struct wpa_scan_res *res,
+ struct os_time *fetch_time)
{
const u8 *ssid, *p2p;
struct wpa_bss *bss;
@@ -595,9 +600,9 @@
* (to save memory) */
bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
if (bss == NULL)
- bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
+ bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
else
- bss = wpa_bss_update(wpa_s, bss, res);
+ bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
if (bss == NULL)
return;
@@ -865,6 +870,29 @@
/**
+ * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @idf: Smallest allowed identifier assigned for the entry
+ * @idf: Largest allowed identifier assigned for the entry
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
+ * smallest id value to be fetched within the specified range without the
+ * caller having to know the exact id.
+ */
+struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
+ unsigned int idf, unsigned int idl)
+{
+ struct wpa_bss *bss;
+ dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
+ if (bss->id >= idf && bss->id <= idl)
+ return bss;
+ }
+ return NULL;
+}
+
+
+/**
* wpa_bss_get_ie - Fetch a specified information element from a BSS entry
* @bss: BSS table entry
* @ie: Information element identitifier (WLAN_EID_*)
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 01f6c59..9f14d0e 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -97,7 +97,8 @@
void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res);
+ struct wpa_scan_res *res,
+ struct os_time *fetch_time);
void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan);
int wpa_bss_init(struct wpa_supplicant *wpa_s);
@@ -111,6 +112,8 @@
struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
const u8 *dev_addr);
struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
+struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
+ unsigned int idf, unsigned int idl);
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2c52c68..ee634a5 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2980,10 +2980,11 @@
{ 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 },
+ { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff),
+ CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dh_pubkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dh_privkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dev_pw), CFG_CHANGED_NFC_PASSWORD_TOKEN },
{ STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
{ INT(p2p_go_max_inactivity), 0 },
{ INT_RANGE(auto_interworking, 0, 1), 0 },
@@ -3020,6 +3021,8 @@
"parse '%s'.", line, pos);
ret = -1;
}
+ if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
+ config->wps_nfc_pw_from_config = 1;
config->changed_parameters |= field->changed_flag;
break;
}
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 0c3cb9a..2b88bb5 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -220,6 +220,7 @@
#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
#define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
+#define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -706,6 +707,15 @@
char *autoscan;
/**
+ * wps_nfc_pw_from_config - NFC Device Password was read from config
+ *
+ * This parameter can be determined whether the NFC Device Password was
+ * included in the configuration (1) or generated dynamically (0). Only
+ * the former case is re-written back to the configuration file.
+ */
+ int wps_nfc_pw_from_config;
+
+ /**
* wps_nfc_dev_pw_id - NFC Device Password ID for password token
*/
int wps_nfc_dev_pw_id;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 50c3533..f29f7a6 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -950,12 +950,16 @@
#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);
+ if (config->wps_nfc_pw_from_config) {
+ 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);
+ }
if (config->ext_password_backend)
fprintf(f, "ext_password_backend=%s\n",
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index d3c87da..dbe9153 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -778,6 +778,35 @@
}
+static int wpa_supplicant_ctrl_iface_wps_nfc_config_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_config_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_token(
struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
{
@@ -835,12 +864,13 @@
static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
- char *reply, size_t max_len)
+ char *reply, size_t max_len,
+ int cr)
{
struct wpabuf *buf;
int res;
- buf = wpas_wps_nfc_handover_req(wpa_s);
+ buf = wpas_wps_nfc_handover_req(wpa_s, cr);
if (buf == NULL)
return -1;
@@ -869,9 +899,9 @@
if (os_strcmp(cmd, "NDEF") != 0)
return -1;
- if (os_strcmp(pos, "WPS") == 0) {
- return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
- max_len);
+ if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_req_wps(
+ wpa_s, reply, max_len, os_strcmp(pos, "WPS-CR") == 0);
}
return -1;
@@ -879,12 +909,13 @@
static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
- char *reply, size_t max_len)
+ char *reply, size_t max_len,
+ int ndef, int cr)
{
struct wpabuf *buf;
int res;
- buf = wpas_wps_nfc_handover_sel(wpa_s);
+ buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr);
if (buf == NULL)
return -1;
@@ -904,18 +935,24 @@
size_t max_len)
{
char *pos;
+ int ndef;
pos = os_strchr(cmd, ' ');
if (pos == NULL)
return -1;
*pos++ = '\0';
- if (os_strcmp(cmd, "NDEF") != 0)
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
return -1;
- if (os_strcmp(pos, "WPS") == 0) {
- return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
- max_len);
+ if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_wps(
+ wpa_s, reply, max_len, ndef,
+ os_strcmp(pos, "WPS-CR") == 0);
}
return -1;
@@ -976,6 +1013,76 @@
return ret;
}
+
+static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ size_t len;
+ struct wpabuf *req, *sel;
+ int ret;
+ char *pos, *role, *type, *pos2;
+
+ role = cmd;
+ pos = os_strchr(role, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ type = pos;
+ pos = os_strchr(type, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ pos2 = os_strchr(pos, ' ');
+ if (pos2 == NULL)
+ return -1;
+ *pos2++ = '\0';
+
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ req = wpabuf_alloc(len);
+ if (req == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+ wpabuf_free(req);
+ return -1;
+ }
+
+ len = os_strlen(pos2);
+ if (len & 0x01) {
+ wpabuf_free(req);
+ return -1;
+ }
+ len /= 2;
+
+ sel = wpabuf_alloc(len);
+ if (sel == NULL) {
+ wpabuf_free(req);
+ return -1;
+ }
+ if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+ wpabuf_free(req);
+ wpabuf_free(sel);
+ return -1;
+ }
+
+ if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
+ ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
+ } else {
+ wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
+ "reported: role=%s type=%s", role, type);
+ ret = -1;
+ }
+ wpabuf_free(req);
+ wpabuf_free(sel);
+
+ return ret;
+}
+
#endif /* CONFIG_WPS_NFC */
@@ -3174,10 +3281,17 @@
return 0;
}
- id1 = atoi(cmd + 6);
- bss = wpa_bss_get_id(wpa_s, id1);
- id2 = atoi(ctmp + 1);
- if (id2 == 0)
+ if (*(cmd + 6) == '-')
+ id1 = 0;
+ else
+ id1 = atoi(cmd + 6);
+ ctmp++;
+ if (*ctmp >= '0' && *ctmp <= '9')
+ id2 = atoi(ctmp);
+ else
+ id2 = (unsigned int) -1;
+ bss = wpa_bss_get_id_range(wpa_s, id1, id2);
+ if (id2 == (unsigned int) -1)
bsslast = dl_list_last(&wpa_s->bss_id,
struct wpa_bss,
list_id);
@@ -4803,6 +4917,7 @@
if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+ os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0 ||
os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
(const u8 *) buf, os_strlen(buf));
@@ -4919,6 +5034,9 @@
} 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_CONFIG_TOKEN ", 21) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token(
+ wpa_s, buf + 21, reply, reply_size);
} 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);
@@ -4938,6 +5056,9 @@
} else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
reply_len = -1;
+ } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
+ if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20))
+ 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))
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 8bc6618..5b4a0a4 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1808,6 +1808,9 @@
case WPAS_DBUS_BSS_PROP_RSN:
prop = "RSN";
break;
+ case WPAS_DBUS_BSS_PROP_WPS:
+ prop = "WPS";
+ break;
case WPAS_DBUS_BSS_PROP_IES:
prop = "IEs";
break;
diff --git a/wpa_supplicant/eap_proxy_dummy.mk b/wpa_supplicant/eap_proxy_dummy.mk
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/wpa_supplicant/eap_proxy_dummy.mk
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 945ba4a..871e99c 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -639,6 +639,28 @@
}
+static int bss_is_dmg(struct wpa_bss *bss)
+{
+ return bss->freq > 45000;
+}
+
+
+/*
+ * Test whether BSS is in an ESS.
+ * This is done differently in DMG (60 GHz) and non-DMG bands
+ */
+static int bss_is_ess(struct wpa_bss *bss)
+{
+ if (bss_is_dmg(bss)) {
+ return (bss->caps & IEEE80211_CAP_DMG_MASK) ==
+ IEEE80211_CAP_DMG_AP;
+ }
+
+ return ((bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
+ IEEE80211_CAP_ESS);
+}
+
+
static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group)
@@ -772,9 +794,8 @@
continue;
}
- if (bss->caps & IEEE80211_CAP_IBSS) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - IBSS (adhoc) "
- "network");
+ if (!bss_is_ess(bss)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - not ESS network");
continue;
}
@@ -3051,6 +3072,16 @@
wpas_wps_start_pbc(wpa_s, NULL, 0);
#endif /* CONFIG_WPS */
break;
+ case EVENT_CONNECT_FAILED_REASON:
+#ifdef CONFIG_AP
+ if (!wpa_s->ap_iface || !data)
+ break;
+ hostapd_event_connect_failed_reason(
+ wpa_s->ap_iface->bss[0],
+ data->connect_failed_reason.addr,
+ data->connect_failed_reason.code);
+#endif /* CONFIG_AP */
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
diff --git a/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant/examples/wps-nfc.py
index 0cfc1f6..14acc5b 100755
--- a/wpa_supplicant/examples/wps-nfc.py
+++ b/wpa_supplicant/examples/wps-nfc.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
#
# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
-# Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
@@ -9,12 +9,17 @@
import os
import sys
import time
+import random
+import StringIO
import nfc
import nfc.ndef
import nfc.llcp
import nfc.handover
+import logging
+logging.basicConfig()
+
import wpactrl
wpas_ctrl = '/var/run/wpa_supplicant'
@@ -49,18 +54,34 @@
print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
+def wpas_get_config_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_password_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
+
+
def wpas_get_handover_req():
wpas = wpas_connect()
if (wpas == None):
return None
- return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS").rstrip().decode("hex")
+ return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
-def wpas_put_handover_sel(message):
+def wpas_report_handover(req, sel):
wpas = wpas_connect()
if (wpas == None):
- return
- print wpas.request("NFC_RX_HANDOVER_SEL " + str(message).encode("hex"))
+ return None
+ return wpas.request("NFC_REPORT_HANDOVER INIT WPS " +
+ str(req).encode("hex") + " " +
+ str(sel).encode("hex"))
def wps_handover_init(peer):
@@ -68,14 +89,24 @@
data = wpas_get_handover_req()
if (data == None):
- print "Could not get handover request message from wpa_supplicant"
+ print "Could not get handover request carrier record from wpa_supplicant"
return
- print "Handover request from wpa_supplicant: " + data.encode("hex")
- message = nfc.ndef.Message(data)
- print "Parsed handover request: " + message.pretty()
+ print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+ record = nfc.ndef.Record()
+ f = StringIO.StringIO(data)
+ record._read(f)
+ record = nfc.ndef.HandoverCarrierRecord(record)
+ print "Parsed handover request carrier record:"
+ print record.pretty()
+
+ message = nfc.ndef.HandoverRequestMessage(version="1.2")
+ message.nonce = random.randint(0, 0xffff)
+ message.add_carrier(record, "active")
+
+ print "Handover request:"
+ print message.pretty()
nfc.llcp.activate(peer);
- time.sleep(0.5)
client = nfc.handover.HandoverClient()
try:
@@ -95,9 +126,30 @@
print "Receiving handover response"
message = client._recv()
+ if message is None:
+ print "No response received"
+ nfc.llcp.shutdown()
+ client.close()
+ return
+ if message.type != "urn:nfc:wkt:Hs":
+ print "Response was not Hs - received: " + message.type
+ nfc.llcp.shutdown()
+ client.close()
+ return
+
+ print "Received message"
+ print message.pretty()
+ message = nfc.ndef.HandoverSelectMessage(message)
print "Handover select received"
print message.pretty()
- wpas_put_handover_sel(message)
+
+ for carrier in message.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.wsc":
+ print "WPS carrier type match - send to wpa_supplicant"
+ wpas_report_handover(data, carrier.record)
+ wifi = nfc.ndef.WifiConfigRecord(carrier.record)
+ print wifi.pretty()
print "Remove peer"
nfc.llcp.shutdown()
@@ -124,32 +176,105 @@
time.sleep(0.1)
+def wps_write_config_tag(clf):
+ print "Write WPS config token"
+ data = wpas_get_config_token()
+ if (data == None):
+ print "Could not get WPS config token from wpa_supplicant"
+ return
+
+ print "Touch an NFC tag"
+ while True:
+ tag = clf.poll()
+ if tag == None:
+ time.sleep(0.1)
+ continue
+ break
+
+ print "Tag found - writing"
+ tag.ndef.message = data
+ print "Done - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def wps_write_password_tag(clf):
+ print "Write WPS password token"
+ data = wpas_get_password_token()
+ if (data == None):
+ print "Could not get WPS password token from wpa_supplicant"
+ return
+
+ print "Touch an NFC tag"
+ while True:
+ tag = clf.poll()
+ if tag == None:
+ time.sleep(0.1)
+ continue
+ break
+
+ print "Tag found - writing"
+ tag.ndef.message = data
+ print "Done - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def find_peer(clf):
+ while True:
+ if nfc.llcp.connected():
+ print "LLCP connected"
+ general_bytes = nfc.llcp.startup({})
+ peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
+ if isinstance(peer, nfc.DEP):
+ print "listen -> DEP";
+ if peer.general_bytes.startswith("Ffm"):
+ print "Found DEP"
+ return peer
+ print "mismatch in general_bytes"
+ print peer.general_bytes
+
+ peer = clf.poll(general_bytes)
+ if isinstance(peer, nfc.DEP):
+ print "poll -> DEP";
+ if peer.general_bytes.startswith("Ffm"):
+ print "Found DEP"
+ return peer
+ print "mismatch in general_bytes"
+ print peer.general_bytes
+
+ if peer:
+ print "Found tag"
+ return peer
+
+
def main():
clf = nfc.ContactlessFrontend()
try:
+ if len(sys.argv) > 1 and sys.argv[1] == "write-config":
+ wps_write_config_tag(clf)
+ raise SystemExit
+
+ if len(sys.argv) > 1 and sys.argv[1] == "write-password":
+ wps_write_password_tag(clf)
+ raise SystemExit
+
while True:
print "Waiting for a tag or peer to be touched"
- while True:
- general_bytes = nfc.llcp.startup({})
- tag = clf.poll(general_bytes)
- if tag == None:
- continue
+ tag = find_peer(clf)
+ if isinstance(tag, nfc.DEP):
+ wps_handover_init(tag)
+ continue
- if isinstance(tag, nfc.DEP):
- wps_handover_init(tag)
- break
+ if tag.ndef:
+ wps_tag_read(tag)
+ continue
- if tag.ndef:
- wps_tag_read(tag)
- break
-
- if tag:
- print "Not an NDEF tag - remove tag"
- while tag.is_present:
- time.sleep(0.1)
- break
+ print "Not an NDEF tag - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
except KeyboardInterrupt:
raise SystemExit
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index e1f58a6..3602b07 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -42,6 +42,10 @@
#endif
static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
+static struct wpa_cred * interworking_credentials_available_realm(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+static struct wpa_cred * interworking_credentials_available_3gpp(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
static void interworking_reconnect(struct wpa_supplicant *wpa_s)
@@ -740,10 +744,10 @@
static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
struct wpa_bss *bss)
{
#ifdef INTERWORKING_3GPP
- struct wpa_cred *cred;
struct wpa_ssid *ssid;
const u8 *ie;
int eap_type;
@@ -753,40 +757,6 @@
if (bss->anqp == NULL || bss->anqp->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->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;
@@ -1167,7 +1137,7 @@
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
- struct wpa_cred *cred;
+ struct wpa_cred *cred, *cred_rc, *cred_3gpp;
struct wpa_ssid *ssid;
struct nai_realm *realm;
struct nai_realm_eap *eap = NULL;
@@ -1194,39 +1164,61 @@
return -1;
}
- cred = interworking_credentials_available_roaming_consortium(wpa_s,
- bss);
- if (cred)
- return interworking_connect_roaming_consortium(wpa_s, cred,
+ cred_rc = interworking_credentials_available_roaming_consortium(wpa_s,
+ bss);
+ if (cred_rc) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
+ "consortium matching credential priority %d",
+ cred_rc->priority);
+ }
+
+ cred = interworking_credentials_available_realm(wpa_s, bss);
+ if (cred) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list "
+ "matching credential priority %d",
+ cred->priority);
+ }
+
+ cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss);
+ if (cred_3gpp) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching "
+ "credential priority %d", cred_3gpp->priority);
+ }
+
+ if (cred_rc &&
+ (cred == NULL || cred_rc->priority >= cred->priority) &&
+ (cred_3gpp == NULL || cred_rc->priority >= cred_3gpp->priority))
+ return interworking_connect_roaming_consortium(wpa_s, cred_rc,
bss, ie);
+ if (cred_3gpp &&
+ (cred == NULL || cred_3gpp->priority >= cred->priority)) {
+ return interworking_connect_3gpp(wpa_s, cred_3gpp, bss);
+ }
+
+ if (cred == NULL) {
+ wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
+ "found for " MACSTR, MAC2STR(bss->bssid));
+ return -1;
+ }
+
realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
&count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
- count = 0;
+ return -1;
}
- 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;
- }
+ 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) {
- if (interworking_connect_3gpp(wpa_s, bss) == 0) {
- if (realm)
- nai_realm_free(realm, count);
- return 0;
- }
-
wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
"and EAP method found for " MACSTR,
MAC2STR(bss->bssid));
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 3e02099..6cff577 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -93,6 +93,8 @@
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_group_formation_timeout(void *eloop_ctx,
+ void *timeout_ctx);
static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
int group_added);
static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
@@ -111,8 +113,12 @@
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
+ struct os_time time_tmp_age, entry_ts;
+ time_tmp_age.sec = bss->age / 1000;
+ time_tmp_age.usec = (bss->age % 1000) * 1000;
+ os_time_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
- bss->freq, bss->age, bss->level,
+ bss->freq, &entry_ts, bss->level,
(const u8 *) (bss + 1),
bss->ie_len) > 0)
break;
@@ -333,6 +339,10 @@
if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
+ if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation "
+ "timeout");
if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
@@ -3944,7 +3954,11 @@
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
- wpa_s->conf->p2p_oper_reg_class == 124) {
+ wpa_s->conf->p2p_oper_reg_class == 116 ||
+ wpa_s->conf->p2p_oper_reg_class == 117 ||
+ wpa_s->conf->p2p_oper_reg_class == 124 ||
+ wpa_s->conf->p2p_oper_reg_class == 126 ||
+ wpa_s->conf->p2p_oper_reg_class == 127) {
params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
@@ -5495,10 +5509,29 @@
int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
{
+ int ret;
+
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
- return p2p_in_progress(wpa_s->global->p2p);
+ ret = p2p_in_progress(wpa_s->global->p2p);
+ if (ret == 0) {
+ /*
+ * Check whether there is an ongoing WPS provisioning step (or
+ * other parts of group formation) on another interface since
+ * p2p_in_progress() does not report this to avoid issues for
+ * scans during such provisioning step.
+ */
+ if (wpa_s->global->p2p_group_formation &&
+ wpa_s->global->p2p_group_formation != wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Another interface (%s) "
+ "in group formation",
+ wpa_s->global->p2p_group_formation->ifname);
+ ret = 1;
+ }
+ }
+
+ return ret;
}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 9b71400..91a436a 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1461,15 +1461,17 @@
== WPA_SCAN_LEVEL_DBM) {
int snr = r->level - r->noise;
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d level=%d snr=%d%s flags=0x%x",
+ "noise=%d level=%d snr=%d%s flags=0x%x "
+ "age=%u",
MAC2STR(r->bssid), r->freq, r->qual,
r->noise, r->level, snr,
- snr >= GREAT_SNR ? "*" : "", r->flags);
+ snr >= GREAT_SNR ? "*" : "", r->flags,
+ r->age);
} else {
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d level=%d flags=0x%x",
+ "noise=%d level=%d flags=0x%x age=%u",
MAC2STR(r->bssid), r->freq, r->qual,
- r->noise, r->level, r->flags);
+ r->noise, r->level, r->flags, r->age);
}
pos = (u8 *) (r + 1);
if (r->ie_len)
@@ -1560,6 +1562,13 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
return NULL;
}
+ if (scan_res->fetch_time.sec == 0) {
+ /*
+ * Make sure we have a valid timestamp if the driver wrapper
+ * does not set this.
+ */
+ os_get_time(&scan_res->fetch_time);
+ }
filter_scan_res(wpa_s, scan_res);
#ifdef CONFIG_WPS
@@ -1576,7 +1585,8 @@
wpa_bss_update_start(wpa_s);
for (i = 0; i < scan_res->num; i++)
- wpa_bss_update_scan_res(wpa_s, scan_res->res[i]);
+ wpa_bss_update_scan_res(wpa_s, scan_res->res[i],
+ &scan_res->fetch_time);
wpa_bss_update_end(wpa_s, info, new_scan);
return scan_res;
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6d8b1f5..0630a4b 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -770,6 +770,13 @@
}
+static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -868,6 +875,13 @@
return ret;
}
+
+static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv);
+}
+
#endif /* CONFIG_WPS_NFC */
@@ -2529,6 +2543,9 @@
{ "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
cli_cmd_flag_none,
"[BSSID] = start Wi-Fi Protected Setup: NFC" },
+ { "wps_nfc_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL,
+ cli_cmd_flag_none,
+ "<WPS|NDEF> = build configuration token" },
{ "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL,
cli_cmd_flag_none,
"<WPS|NDEF> = create password token" },
@@ -2547,6 +2564,10 @@
{ "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
cli_cmd_flag_none,
"<hexdump of payload> = report received NFC handover select" },
+ { "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL,
+ cli_cmd_flag_none,
+ "<role> <type> <hexdump of req> <hexdump of sel> = report completed "
+ "NFC handover" },
#endif /* CONFIG_WPS_NFC */
{ "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
cli_cmd_flag_sensitive,
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 725364a..a9af2d6 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -664,8 +664,8 @@
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
struct wpa_ssid *ssid = wpa_s->current_ssid;
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
- MACSTR " completed %s [id=%d id_str=%s]",
- MAC2STR(wpa_s->bssid), "(auth)",
+ MACSTR " completed (auth) [id=%d id_str=%s]",
+ MAC2STR(wpa_s->bssid),
ssid ? ssid->id : -1,
ssid && ssid->id_str ? ssid->id_str : "");
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
@@ -1730,6 +1730,10 @@
zero_addr = 1;
}
+#ifdef CONFIG_TDLS
+ wpa_tdls_teardown_peers(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+
if (addr) {
wpa_drv_deauthenticate(wpa_s, addr, reason_code);
os_memset(&event, 0, sizeof(event));
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 4859774..dfc3b76 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -552,20 +552,35 @@
static int wpa_supplicant_tdls_peer_addset(
void *ctx, const u8 *peer, int add, u16 capability,
- const u8 *supp_rates, size_t supp_rates_len)
+ const u8 *supp_rates, size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len)
{
struct wpa_supplicant *wpa_s = ctx;
struct hostapd_sta_add_params params;
+ os_memset(¶ms, 0, sizeof(params));
+
params.addr = peer;
params.aid = 1;
params.capability = capability;
params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
- params.ht_capabilities = NULL;
+
+ /*
+ * TDLS Setup frames do not contain WMM IEs, hence need to depend on
+ * qosinfo to check if the peer is WMM capable.
+ */
+ if (qosinfo)
+ params.flags |= WPA_STA_WMM;
+
+ params.ht_capabilities = ht_capab;
+ params.qosinfo = qosinfo;
params.listen_interval = 0;
params.supp_rates = supp_rates;
params.supp_rates_len = supp_rates_len;
params.set = !add;
+ params.ext_capab = ext_capab;
+ params.ext_capab_len = ext_capab_len;
return wpa_drv_sta_add(wpa_s, ¶ms);
}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 711c3c0..c89479f 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1830,8 +1830,26 @@
#ifdef CONFIG_WPS_NFC
+struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface)
+ return wpas_ap_wps_nfc_config_token(wpa_s, ndef);
+#endif /* CONFIG_AP */
+ return NULL;
+}
+
+
struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
{
+ if (wpa_s->conf->wps_nfc_pw_from_config) {
+ return wps_nfc_token_build(ndef,
+ wpa_s->conf->wps_nfc_dev_pw_id,
+ wpa_s->conf->wps_nfc_dh_pubkey,
+ wpa_s->conf->wps_nfc_dev_pw);
+ }
+
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,
@@ -1977,15 +1995,20 @@
}
-struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s)
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int cr)
{
+ if (cr)
+ return ndef_build_wifi_hc(1);
return ndef_build_wifi_hr();
}
-struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s)
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int cr)
{
- return NULL;
+ if (!cr)
+ return NULL;
+ return wpas_ap_wps_nfc_handover_sel(wpa_s, ndef);
}
@@ -2015,6 +2038,17 @@
return ret;
}
+
+int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ wpa_printf(MSG_DEBUG, "NFC: WPS connection handover reported");
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in request", req);
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in select", sel);
+ return wpas_wps_nfc_rx_handover_sel(wpa_s, sel);
+}
+
#endif /* CONFIG_WPS_NFC */
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index dd0dc60..5bc5ffa 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -62,16 +62,22 @@
int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
int wpas_wps_in_progress(struct wpa_supplicant *wpa_s);
void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef);
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);
-struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s);
-struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int cr);
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int cr);
int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
const struct wpabuf *data);
int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
const struct wpabuf *data);
+int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel);
void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);