OSDN Git Service

Accumulative patch from commit b618a469c42120e984ab1c85ed6058504d1fca78
authorDmitry Shmidt <dimitrysh@google.com>
Wed, 20 Feb 2013 22:34:59 +0000 (14:34 -0800)
committerDmitry Shmidt <dimitrysh@google.com>
Wed, 20 Feb 2013 22:34:59 +0000 (14:34 -0800)
  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>
83 files changed:
hostapd/README-WPS
hostapd/config_file.c
hostapd/ctrl_iface.c
hostapd/hostapd_cli.c
hostapd/wps-ap-nfc.py [new file with mode: 0755]
src/ap/ap_config.h
src/ap/drv_callbacks.c
src/ap/hostapd.h
src/ap/hw_features.c
src/ap/ieee802_11.c
src/ap/ieee802_11_ht.c
src/ap/wps_hostapd.c
src/ap/wps_hostapd.h
src/common/ieee802_11_defs.h
src/common/wpa_ctrl.h
src/drivers/driver.h
src/drivers/driver_common.c
src/drivers/driver_nl80211.c
src/drivers/driver_test.c
src/drivers/nl80211_copy.h
src/eap_common/eap_gpsk_common.c
src/eap_common/eap_gpsk_common.h
src/eap_peer/eap.c
src/eap_peer/eap.h
src/eap_peer/eap_aka.c
src/eap_peer/eap_fast.c
src/eap_peer/eap_gpsk.c
src/eap_peer/eap_i.h
src/eap_peer/eap_ikev2.c
src/eap_peer/eap_peap.c
src/eap_peer/eap_proxy.h [new file with mode: 0644]
src/eap_peer/eap_proxy_dummy.c [new file with mode: 0644]
src/eap_peer/eap_psk.c
src/eap_peer/eap_sake.c
src/eap_peer/eap_sim.c
src/eap_peer/eap_tls.c
src/eap_peer/eap_tls_common.c
src/eap_peer/eap_tls_common.h
src/eap_peer/eap_ttls.c
src/eap_peer/eap_wsc.c
src/eap_server/ikev2.c
src/eapol_supp/eapol_supp_sm.c
src/p2p/p2p.c
src/p2p/p2p.h
src/p2p/p2p_i.h
src/p2p/p2p_invitation.c
src/p2p/p2p_pd.c
src/rsn_supp/tdls.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_i.h
src/rsn_supp/wpa_ie.c
src/rsn_supp/wpa_ie.h
src/utils/os_unix.c
src/wps/ndef.c
src/wps/wps.c
src/wps/wps.h
src/wps/wps_common.c
src/wps/wps_enrollee.c
src/wps/wps_i.h
src/wps/wps_registrar.c
wpa_supplicant/Android.mk
wpa_supplicant/Makefile
wpa_supplicant/README-WPS
wpa_supplicant/ap.c
wpa_supplicant/ap.h
wpa_supplicant/bss.c
wpa_supplicant/bss.h
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/ctrl_iface.c
wpa_supplicant/dbus/dbus_new.c
wpa_supplicant/eap_proxy_dummy.mk [new file with mode: 0644]
wpa_supplicant/events.c
wpa_supplicant/examples/wps-nfc.py
wpa_supplicant/interworking.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/scan.c
wpa_supplicant/wpa_cli.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpas_glue.c
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index 87a6f91..654b5bc 100644 (file)
@@ -338,3 +338,17 @@ If the NFC tag contains a password token, the token is added to the
 internal Registrar. This allows station Enrollee from which the password
 token was received to run through WPS protocol to provision the
 credential.
+
+"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.
index 7b22dfd..e29ae2f 100644 (file)
@@ -2627,15 +2627,19 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                                           "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
index 93b740e..f20721b 100644 (file)
@@ -352,6 +352,59 @@ static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
 
        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 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
        } 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
index b693fa0..1537275 100644 (file)
@@ -475,6 +475,29 @@ static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
        }
        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 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
        { "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 (executable)
index 0000000..32a0214
--- /dev/null
@@ -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()
index 4742107..6606f72 100644 (file)
@@ -365,6 +365,7 @@ struct hostapd_bss_config {
        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;
index 8980bec..6d22d49 100644 (file)
@@ -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_ch_switch(struct hostapd_data *hapd, int freq, int ht,
 }
 
 
+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 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                        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;
index 2827232..8ab4f3e 100644 (file)
@@ -305,6 +305,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                        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);
index 923b698..37112bd 100644 (file)
@@ -443,7 +443,6 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
                           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);
index 129c5b5..8baa15e 100644 (file)
@@ -1601,7 +1601,7 @@ static void handle_action(struct hostapd_data *hapd,
                                               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);
                }
index 6c3696f..6483e1c 100644 (file)
@@ -133,8 +133,7 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
        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;
index 5ce4f1b..dfe77ad 100644 (file)
@@ -1583,8 +1583,25 @@ struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
 }
 
 
+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,
index 4e5026b..a2c2cf0 100644 (file)
@@ -35,6 +35,7 @@ int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
                             const struct wpabuf *data);
 struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
                                             int ndef);
+struct wpabuf * hostapd_wps_nfc_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);
index f72c0d4..6a7fff6 100644 (file)
 /* 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
index 84f1195..77c48cf 100644 (file)
@@ -150,6 +150,8 @@ extern "C" {
 #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 */
 
index 5e8fd65..5dee2e6 100644 (file)
@@ -122,6 +122,13 @@ struct hostapd_hw_modes {
 #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_res {
  * 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 @@ struct hostapd_sta_add_params {
        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 @@ enum wpa_event_type {
         *
         * 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 @@ union wpa_event_data {
                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;
 };
 
 /**
index 418cf1a..565a01b 100644 (file)
@@ -79,6 +79,7 @@ const char * event_to_string(enum wpa_event_type event)
        E2S(EAPOL_TX_STATUS);
        E2S(CH_SWITCH);
        E2S(WNM);
+       E2S(CONNECT_FAILED_REASON);
        }
 
        return "UNKNOWN";
index d133bad..a134992 100644 (file)
@@ -2162,6 +2162,43 @@ static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
+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 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        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 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        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 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        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 @@ static int wpa_driver_nl80211_sta_add(void *priv,
                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;
index bd65dd8..c99802a 100644 (file)
@@ -1318,11 +1318,12 @@ static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
        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;
index e3e19f8..c46bb01 100644 (file)
  *     %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
  *     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
  *     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
  * @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 @@ enum nl80211_commands {
 
        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 @@ enum nl80211_commands {
  * @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 @@ enum nl80211_commands {
  *     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 @@ enum nl80211_attrs {
        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 @@ enum nl80211_iftype {
  *     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 @@ enum nl80211_sta_flags {
        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 @@ enum nl80211_sta_bss_param {
  * @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 @@ enum nl80211_sta_bss_param {
  * @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 @@ enum nl80211_sta_info {
        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 @@ enum nl80211_band_attr {
  *     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 @@ enum nl80211_frequency_attr {
        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_mntr_flags {
 };
 
 /**
+ * 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 @@ enum nl80211_mntr_flags {
  *     (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 @@ enum nl80211_meshconf_params {
        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 @@ enum nl80211_tx_power_setting {
  *     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 @@ enum nl80211_wowlan_packet_pattern_attr {
        __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 @@ enum nl80211_wowlan_packet_pattern_attr {
  * @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 @@ struct nl80211_wowlan_pattern_support {
        __u32 max_patterns;
        __u32 min_pattern_len;
        __u32 max_pattern_len;
+       __u32 max_pkt_offset;
 } __attribute__((packed));
 
 /**
@@ -2861,12 +3010,17 @@ struct nl80211_wowlan_pattern_support {
  * @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 @@ struct nl80211_wowlan_pattern_support {
  * @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 @@ enum nl80211_wowlan_triggers {
        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 @@ enum nl80211_wowlan_triggers {
 };
 
 /**
+ * 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 @@ enum nl80211_iface_limit_attrs {
  *     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 @@ enum nl80211_if_combination_attrs {
        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 @@ enum nl80211_ap_sme_features {
  *     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 @@ enum nl80211_feature_flags {
        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_probe_resp_offload_support_attr {
  * 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 @@ enum nl80211_scan_flags {
        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 */
index 7d106dd..7a33215 100644 (file)
@@ -340,6 +340,141 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
 }
 
 
+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
index e3d2b6b..fbcd547 100644 (file)
@@ -53,6 +53,12 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
                         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);
index 85c242a..4df8853 100644 (file)
@@ -161,6 +161,8 @@ SM_STATE(EAP, INITIALIZE)
        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 @@ SM_STATE(EAP, METHOD)
                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 @@ void eap_sm_abort(struct eap_sm *sm)
        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 @@ void eap_notify_lower_layer_success(struct eap_sm *sm)
 
 
 /**
+ * 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
index 8bccef1..f87f9b3 100644 (file)
@@ -306,6 +306,7 @@ void eap_set_force_disabled(struct eap_sm *sm, int disabled);
 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);
index 59861cb..dc424d7 100644 (file)
@@ -1340,6 +1340,28 @@ static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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 @@ int eap_peer_aka_register(void)
        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 @@ int eap_peer_aka_prime_register(void)
        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;
index 7ca5288..3b8d803 100644 (file)
@@ -53,6 +53,8 @@ struct eap_fast_data {
        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 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
                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 @@ static struct wpabuf * eap_fast_process_crypto_binding(
                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 @@ static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
                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_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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 @@ int eap_peer_fast_register(void)
        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;
index 2bd0d48..8a0644d 100644 (file)
@@ -23,8 +23,8 @@ struct eap_gpsk_data {
        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 @@ static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
                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_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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 @@ int eap_peer_gpsk_register(void)
        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)
index dd94317..62c867c 100644 (file)
@@ -261,6 +261,19 @@ struct eap_method {
         * 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 @@ struct eap_sm {
        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;
index a227f8b..09a655e 100644 (file)
@@ -475,6 +475,36 @@ static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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 @@ int eap_peer_ikev2_register(void)
        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)
index 7fff145..3b93209 100644 (file)
@@ -56,6 +56,8 @@ struct eap_peap_data {
        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 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
        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 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
                                           "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 @@ static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
        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_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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 @@ int eap_peer_peap_register(void)
        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 (file)
index 0000000..3b4dcef
--- /dev/null
@@ -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 (file)
index 0000000..cd97fb6
--- /dev/null
@@ -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;
+}
index d618fcf..cd0e3f9 100644 (file)
@@ -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 @@ static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
        }
        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_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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 @@ int eap_peer_psk_register(void)
        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);
index e072f46..431519c 100644 (file)
@@ -452,6 +452,28 @@ static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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 @@ int eap_peer_sake_register(void)
        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);
index c936a44..82ea18d 100644 (file)
@@ -1084,6 +1084,29 @@ static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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 @@ int eap_peer_sim_register(void)
        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;
index 061a72b..d2066cd 100644 (file)
@@ -21,6 +21,8 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv);
 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 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv)
                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 @@ static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
        } 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 @@ static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
        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_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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 @@ int eap_peer_tls_register(void)
        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;
index aedd85a..a777bb0 100644 (file)
@@ -340,6 +340,52 @@ fail:
 
 
 /**
+ * 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
index 91d3a25..1a5e0f8 100644 (file)
@@ -94,6 +94,9 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
 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,
index 9360a42..5091bf0 100644 (file)
@@ -54,6 +54,8 @@ struct eap_ttls_data {
        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 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
        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 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm,
        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 @@ static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
        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_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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 @@ int eap_peer_ttls_register(void)
        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;
index d007a57..f358156 100644 (file)
@@ -194,7 +194,8 @@ static void * eap_wsc_init(struct eap_sm *sm)
                        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;
index 0e77efb..512ba30 100644 (file)
@@ -990,7 +990,7 @@ static int ikev2_build_kei(struct ikev2_initiator_data *data,
         */
        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);
index f90fb62..2e56086 100644 (file)
@@ -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 @@ struct eapol_sm {
        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_STATE(SUPP_BE, SUCCESS)
        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 @@ static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
        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 @@ void eapol_sm_step(struct eapol_sm *sm)
                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 @@ int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
                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 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
                        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 @@ void eapol_sm_notify_config(struct eapol_sm *sm,
                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 @@ void eapol_sm_notify_config(struct eapol_sm *sm,
        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 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
        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 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
                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 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
                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 @@ void eapol_sm_deinit(struct eapol_sm *sm)
        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);
index aaacc9a..985227c 100644 (file)
@@ -617,8 +617,18 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
        }
 
        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 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
  *     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 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
  * 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 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
                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 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
                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 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
 
        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 @@ int p2p_other_scan_completed(struct p2p_data *p2p)
                "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 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
 
 
 int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
-                        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;
 }
index 18e733b..0663fbb 100644 (file)
@@ -1200,7 +1200,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
  * @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 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
  * start of a pending operation, e.g., to start a pending GO negotiation.
  */
 int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
-                        unsigned int age, int level, const u8 *ies,
+                        struct os_time *rx_time, int level, const u8 *ies,
                         size_t ies_len);
 
 /**
index 712544b..b2a3d3f 100644 (file)
@@ -403,6 +403,8 @@ struct p2p_data {
        u8 *find_dev_id;
        u8 find_dev_id_buf[ETH_ALEN];
 
+       struct os_time find_start; /* time of last p2p_find start */
+
        struct p2p_group **groups;
        size_t num_groups;
 
@@ -706,7 +708,7 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p,
 void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
                      struct p2p_device *dev, struct p2p_message *msg);
 int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
-                  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,
index ac67932..9283113 100644 (file)
@@ -176,7 +176,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
                        "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 "
index ca33f17..44db682 100644 (file)
@@ -152,7 +152,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                        "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 "
index 9a79d28..09adc19 100644 (file)
@@ -120,6 +120,13 @@ struct wpa_tdls_peer {
 
        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 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
        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 @@ int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
        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_supp_rates(const struct wpa_eapol_ie_parse *kde,
 }
 
 
+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 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
        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:
 
 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 @@ static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
 #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 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
        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 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
        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 @@ int wpa_tdls_init(struct wpa_sm *sm)
 }
 
 
+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;
index 2c989b7..6679dda 100644 (file)
@@ -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 @@ struct wpa_sm_ctx {
        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_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
 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);
index 9f9e641..5dae5de 100644 (file)
@@ -283,12 +283,16 @@ static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper,
 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 */
index 3d75365..252737f 100644 (file)
@@ -427,6 +427,11 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
                } 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)
index 5afdfe9..b212711 100644 (file)
@@ -49,6 +49,9 @@ struct wpa_eapol_ie_parse {
        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,
index 23a93be..cc22e83 100644 (file)
@@ -257,7 +257,11 @@ int os_program_init(void)
         * 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;
 
index a48a2d7..96685d2 100644 (file)
@@ -170,10 +170,30 @@ struct wpabuf * ndef_build_wifi(const struct wpabuf *buf)
 }
 
 
+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 @@ struct wpabuf * ndef_build_wifi_hr(void)
        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;
index 2575705..ff4b20d 100644 (file)
@@ -53,12 +53,18 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                }
                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 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                          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 @@ void wps_deinit(struct wps_data *data)
        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);
index c6b7099..39fce56 100644 (file)
@@ -810,6 +810,8 @@ u16 wps_config_methods_str2bin(const char *str);
 struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
                                       const struct wpabuf *pubkey,
                                       const struct wpabuf *dev_pw);
+struct wpabuf * wps_nfc_token_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 @@ struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
 /* 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
index 68d9f0a..0897b7b 100644 (file)
@@ -562,11 +562,34 @@ struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
 
 
 #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 @@ struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
        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 */
index 837b941..9c0cebb 100644 (file)
@@ -837,6 +837,39 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
 }
 
 
+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 @@ static enum wps_process_res wps_process_m2(struct wps_data *wps,
 
        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;
        }
index 8110894..6efc3bf 100644 (file)
@@ -71,6 +71,9 @@ struct wps_data {
        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
index 11e7e84..f01e3b3 100644 (file)
@@ -1363,6 +1363,14 @@ static int wps_get_dev_password(struct wps_data *wps)
        } 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 "
index 7545ab2..4332d82 100644 (file)
@@ -504,6 +504,13 @@ CONFIG_EAP_SIM_COMMON=y
 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)
index f39a3d7..da2abfc 100644 (file)
@@ -482,6 +482,13 @@ CONFIG_EAP_SIM_COMMON=y
 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)
index 1ea9843..2a1dda5 100644 (file)
@@ -336,6 +336,16 @@ wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
 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 @@ type. The reply data is contents for the Handover Select Message
 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.
index 85ee6cb..82b7e19 100644 (file)
@@ -848,6 +848,34 @@ void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s)
        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 */
 
 
index 536064f..fd4c25a 100644 (file)
@@ -52,5 +52,9 @@ int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
 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 */
index 87b7db8..c50de53 100644 (file)
@@ -224,7 +224,8 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
 }
 
 
-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 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
        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 int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
 
 static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
                                    const u8 *ssid, size_t ssid_len,
-                                   struct wpa_scan_res *res)
+                                   struct wpa_scan_res *res,
+                                   struct os_time *fetch_time)
 {
        struct wpa_bss *bss;
 
@@ -324,7 +327,7 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
                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 void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
 
 static struct wpa_bss *
 wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
-              struct wpa_scan_res *res)
+              struct 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 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
  * 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 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
         * (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 @@ struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
 
 
 /**
+ * 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_*)
index 01f6c59..9f14d0e 100644 (file)
@@ -97,7 +97,8 @@ struct wpa_bss {
 
 void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
-                            struct wpa_scan_res *res);
+                            struct 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_bssid(struct wpa_supplicant *wpa_s,
 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,
index 2c52c68..ee634a5 100644 (file)
@@ -2980,10 +2980,11 @@ static const struct global_parse_data global_fields[] = {
        { 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 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
                                   "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;
        }
index 0c3cb9a..2b88bb5 100644 (file)
@@ -220,6 +220,7 @@ struct wpa_cred {
 #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 @@ struct wpa_config {
        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;
index 50c3533..f29f7a6 100644 (file)
@@ -950,12 +950,16 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
 #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",
index d3c87da..dbe9153 100644 (file)
@@ -778,6 +778,35 @@ static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
 }
 
 
+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 wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
 
 
 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 @@ static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
        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_req(struct wpa_supplicant *wpa_s,
 
 
 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 @@ static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
                                          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 @@ static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
        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 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
                                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 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        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 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } 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 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } 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))
index 8bc6618..5b4a0a4 100644 (file)
@@ -1808,6 +1808,9 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
        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 (file)
index 0000000..e69de29
index 945ba4a..871e99c 100644 (file)
@@ -639,6 +639,28 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 }
 
 
+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 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                        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 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                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;
index 0cfc1f6..14acc5b 100755 (executable)
@@ -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 @@ def wpas_tag_read(message):
     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 @@ def wps_handover_init(peer):
 
     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 @@ def wps_handover_init(peer):
 
     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 @@ def wps_tag_read(tag):
         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
-
-                if isinstance(tag, nfc.DEP):
-                    wps_handover_init(tag)
-                    break
-
-                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
+            tag = find_peer(clf)
+            if isinstance(tag, nfc.DEP):
+                wps_handover_init(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
index e1f58a6..3602b07 100644 (file)
 #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_set_hs20_params(struct wpa_supplicant *wpa_s,
 
 
 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 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
        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 @@ fail:
 
 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 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
                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));
index 3e02099..6cff577 100644 (file)
@@ -93,6 +93,8 @@ static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_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 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
 
        for (i = 0; i < scan_res->num; i++) {
                struct wpa_scan_res *bss = scan_res->res[i];
+               struct os_time time_tmp_age, entry_ts;
+               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 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
 
        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 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
                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_disconnect(struct wpa_supplicant *wpa_s)
 
 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;
 }
 
 
index 9b71400..91a436a 100644 (file)
@@ -1461,15 +1461,17 @@ static void dump_scan_res(struct wpa_scan_results *scan_res)
                    == 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_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
                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_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
 
        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;
index 6d8b1f5..0630a4b 100644 (file)
@@ -770,6 +770,13 @@ static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+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 @@ static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
        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 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "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 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "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,
index 725364a..a9af2d6 100644 (file)
@@ -664,8 +664,8 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
 #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 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                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));
index 4859774..dfc3b76 100644 (file)
@@ -552,20 +552,35 @@ static int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *peer)
 
 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(&params, 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, &params);
 }
index 711c3c0..c89479f 100644 (file)
@@ -1830,8 +1830,26 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
 
 #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 @@ int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
 }
 
 
-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 @@ int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
        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 */
 
 
index dd0dc60..5bc5ffa 100644 (file)
@@ -62,16 +62,22 @@ struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
 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);