OSDN Git Service

Accumulative patch from commit 1075b2957169d8f9d6dddd7679339c751dc9515b
authorDmitry Shmidt <dimitrysh@google.com>
Thu, 11 Jul 2013 17:46:32 +0000 (10:46 -0700)
committerDmitry Shmidt <dimitrysh@google.com>
Thu, 11 Jul 2013 18:25:16 +0000 (11:25 -0700)
1075b29 P2P: Report group formation failure on error to start GO mode
b62b29e Do not block on ctrl_iface monitor events
eb7ddbf WPS: Stop SSDP service before freeing the pending entries
98cbc0a Remove forgotten Xcode defines
0b9d3b2 Interworking: Relax 3GPP info PLMN matching for MNC
c7a67a7 WPS: Disconnect when removing existing WPS network block
fe65847 EAP-EKE: Add server implementation
7e7610d EAP-EKE: Add peer implementation
489202d EAP-SAKE: Use configured server identity
a607b42 EAP-PSK: Use configured server identity
15b042b EAP-MSCHAPv2: Use configured server identity
162865b EAP-IKEv2 server: Use configured server identity
8f89d82 EAP-GPSK server: Use configured server identity
67fe933 Add server identity configuration for EAP server
06aeff5 dbus: Register the AutoScan method call at the right place
78f79fe P2P: Do not add ctrl interface for P2P_DEVICE (p2p-dev-*)
1c42b42 P2P: Fix TDLS and l2_packet init without P2P Device interface
9e6a321 Fix non-P2P build after the P2P_DEVICE changes
d53d259 Fix build with older OpenSSL versions
54d4ba4 nl80211: Silence a compiler warning with older gcc versions
2e5ba4b P2P: Derive group interface name bit more sensibly
c68f620 P2P: Create P2P Device interface if supported
851b0c5 nl80211: Do not indicate P2P_DEVICE support by default
bb4028f P2P: Ignore p2p_no_group_iface when driver advertizes P2P_DEVICE support
7940c79 nl80211: Use wdev id when cancelling wait for frame using P2P_DEVICE
f608081 nl80211: Verify P2P GO/client address with all interface addresses
5fbcb45 nl80211: Fix determining phy name for P2P Device
27ce1d6 nl80211: Fix nl80211_get_wiphy_index() for P2P Device
080585c Add support for OCSP stapling to validate server certificate
72950ed P2P: Remove a call to wpas_p2p_deinit_global()
ab7a1ad nl80211: Fix P2P group interface creating using P2P Device
fa93de4 nl80211: Use wdev_id in nl80211_create_iface_once()
fdc554b nl80211: Use wdev id to obtain P2P Device scan results
597b94f nl80211: Add .get_mac_addr() callback for P2P Device
8e12685 nl80211: Rework setting interface mode
91724d6 nl80211: Introduce i802_set_iface_flags()
eb4582f nl80211: Remove P2P Device interface upon .deinit()
f632e48 nl80211: Fix P2P Device interface initialization
e472e1b nl80211: Handle creation of P2P Device interface
01517c8 nl80211: Allow Android P2P functionality
6bae92e nl80211: Add support for P2P Device in add interface
d6dcfcd nl80211: Add a handler to create_interface
d3aaef8 nl80211: Hold wdev identification for P2P Device
7aad838 nl80211: Identify if nl80211 is capable of P2P Device abstraction
6a71413 nl80211: Rename is_p2p_interface
8393e1a nl80211: Print interface name on set_key()
80ebfd9 VLAN: Avoid access to non-existing interfaces
4345fe9 bridge: Track inter-BSS usage
459eee9 bridge: Use safe default bridge interface
2aaeedf bridge: Give bridge name in per-bss configuration
8a901d7 D-Bus: Emit signal when a station is authorized or deauthorized
9578329 Add AVG_RSSI report in signal_poll
2cc8d8f Add bandwidth and center freq info to signal_poll
1e0e943 Remove 802.11b rates only in case of P2P group operation
2090a0b nl80211: Add prints for kernel events
8743676 TDLS: Validate ext_supp_rates in copy_supp_rates
85b4eac P2P: Do not reply to 802.11b-only Probe Request frames as GO
ec7b97a Interworking: Add support for using eap_proxy offload
4331263 Fix session timeout after ANQP dummy STA entry with SME-in-driver
56cb4e1 wpadebug: Add option to ignore SSL errors
aa20e1a Remove CONFIG_NO_WPA2 build parameter
5d5c4ee Remove compiler warnings with CONFIG_NO_SCAN_PROCESSING
9aaa695 Remove compiler warnings if TDLS is enabled without WPA2
84ae1d4 Fix WNM build without WPA2
c33d5eb Fix build without WPA2 or EAP
1aef400 IBSS RSN: Implement disconnect() callback using sta_deauth()

Change-Id: I4593be5b1478f6532da917423b1d2afa95fb8020
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
78 files changed:
hostapd/Android.mk
hostapd/Makefile
hostapd/config_file.c
hostapd/defconfig
hostapd/eap_register.c
hostapd/hostapd.conf
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/authsrv.c
src/ap/beacon.c
src/ap/drv_callbacks.c
src/ap/hostapd.h
src/ap/ieee802_11.c
src/ap/ieee802_1x.c
src/ap/vlan_init.c
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
src/common/wpa_common.c
src/crypto/tls.h
src/crypto/tls_openssl.c
src/drivers/driver.h
src/drivers/driver_nl80211.c
src/eap_common/eap_defs.h
src/eap_common/eap_eke_common.c [new file with mode: 0644]
src/eap_common/eap_eke_common.h [new file with mode: 0644]
src/eap_peer/eap_config.h
src/eap_peer/eap_eke.c [new file with mode: 0644]
src/eap_peer/eap_methods.h
src/eap_peer/eap_tls_common.c
src/eap_server/eap.h
src/eap_server/eap_i.h
src/eap_server/eap_methods.h
src/eap_server/eap_server.c
src/eap_server/eap_server_eke.c [new file with mode: 0644]
src/eap_server/eap_server_gpsk.c
src/eap_server/eap_server_ikev2.c
src/eap_server/eap_server_mschapv2.c
src/eap_server/eap_server_psk.c
src/eap_server/eap_server_sake.c
src/eapol_auth/eapol_auth_sm.c
src/eapol_auth/eapol_auth_sm.h
src/p2p/p2p.c
src/radius/radius_server.c
src/radius/radius_server.h
src/rsn_supp/pmksa_cache.c
src/rsn_supp/pmksa_cache.h
src/rsn_supp/preauth.c
src/rsn_supp/preauth.h
src/rsn_supp/tdls.c
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_ie.c
src/utils/build_config.h
src/wps/wps_upnp.c
wpa_supplicant/Android.mk
wpa_supplicant/Makefile
wpa_supplicant/android.config
wpa_supplicant/ap.c
wpa_supplicant/config.c
wpa_supplicant/ctrl_iface.c
wpa_supplicant/ctrl_iface_unix.c
wpa_supplicant/dbus/dbus_new.c
wpa_supplicant/dbus/dbus_new.h
wpa_supplicant/defconfig
wpa_supplicant/driver_i.h
wpa_supplicant/eap_register.c
wpa_supplicant/events.c
wpa_supplicant/ibss_rsn.c
wpa_supplicant/interworking.c
wpa_supplicant/main.c
wpa_supplicant/notify.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wpas_glue.c
wpa_supplicant/wps_supplicant.c

index 1c2e1f5..1054dc0 100644 (file)
@@ -367,6 +367,13 @@ OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c
 NEED_SHA256=y
 endif
 
+ifdef CONFIG_EAP_EKE
+L_CFLAGS += -DEAP_SERVER_EKE
+OBJS += src/eap_server/eap_server_eke.c src/eap_common/eap_eke_common.c
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+endif
+
 ifdef CONFIG_EAP_VENDOR_TEST
 L_CFLAGS += -DEAP_SERVER_VENDOR_TEST
 OBJS += src/eap_server/eap_server_vendor_test.c
index 26cc2b5..a30a244 100644 (file)
@@ -323,6 +323,13 @@ OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o
 NEED_SHA256=y
 endif
 
+ifdef CONFIG_EAP_EKE
+CFLAGS += -DEAP_SERVER_EKE
+OBJS += ../src/eap_server/eap_server_eke.o ../src/eap_common/eap_eke_common.o
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+endif
+
 ifdef CONFIG_EAP_VENDOR_TEST
 CFLAGS += -DEAP_SERVER_VENDOR_TEST
 OBJS += ../src/eap_server/eap_server_vendor_test.o
index 231b0f9..8e6f35a 100644 (file)
@@ -1689,6 +1689,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                                   sizeof(conf->bss[0].iface));
                } else if (os_strcmp(buf, "bridge") == 0) {
                        os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
+               } else if (os_strcmp(buf, "vlan_bridge") == 0) {
+                       os_strlcpy(bss->vlan_bridge, pos,
+                                  sizeof(bss->vlan_bridge));
                } else if (os_strcmp(buf, "wds_bridge") == 0) {
                        os_strlcpy(bss->wds_bridge, pos,
                                   sizeof(bss->wds_bridge));
@@ -1830,6 +1833,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        bss->private_key_passwd = os_strdup(pos);
                } else if (os_strcmp(buf, "check_crl") == 0) {
                        bss->check_crl = atoi(pos);
+               } else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
+                       os_free(bss->ocsp_stapling_response);
+                       bss->ocsp_stapling_response = os_strdup(pos);
                } else if (os_strcmp(buf, "dh_file") == 0) {
                        os_free(bss->dh_file);
                        bss->dh_file = os_strdup(pos);
@@ -2628,6 +2634,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        bss->upc = os_strdup(pos);
                } else if (os_strcmp(buf, "pbc_in_m1") == 0) {
                        bss->pbc_in_m1 = atoi(pos);
+               } else if (os_strcmp(buf, "server_id") == 0) {
+                       os_free(bss->server_id);
+                       bss->server_id = os_strdup(pos);
 #ifdef CONFIG_WPS_NFC
                } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
                        bss->wps_nfc_dev_pw_id = atoi(pos);
index 317fe74..c288f46 100644 (file)
@@ -117,6 +117,9 @@ CONFIG_EAP_TTLS=y
 # Trusted Network Connect (EAP-TNC)
 #CONFIG_EAP_TNC=y
 
+# EAP-EKE for the integrated EAP server
+#CONFIG_EAP_EKE=y
+
 # PKCS#12 (PFX) support (used to read private key and certificate file from
 # a file that usually has extension .p12 or .pfx)
 CONFIG_PKCS12=y
index 0a7ff91..981e539 100644 (file)
@@ -134,5 +134,10 @@ int eap_server_register_methods(void)
                ret = eap_server_pwd_register();
 #endif /* EAP_SERVER_PWD */
 
+#ifdef EAP_SERVER_EKE
+       if (ret == 0)
+               ret = eap_server_eke_register();
+#endif /* EAP_SERVER_EKE */
+
        return ret;
 }
index be15b86..68c4069 100644 (file)
@@ -666,6 +666,11 @@ eap_server=0
 # Passphrase for private key
 #private_key_passwd=secret passphrase
 
+# Server identity
+# EAP methods that provide mechanism for authenticated server identity delivery
+# use this value. If not set, "hostapd" is used as a default.
+#server_id=server.example.com
+
 # Enable CRL verification.
 # Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
 # valid CRL signed by the CA is required to be included in the ca_cert file.
@@ -677,6 +682,20 @@ eap_server=0
 # 2 = check all CRLs in the certificate path
 #check_crl=1
 
+# Cached OCSP stapling response (DER encoded)
+# If set, this file is sent as a certificate status response by the EAP server
+# if the EAP peer requests certificate status in the ClientHello message.
+# This cache file can be updated, e.g., by running following command
+# periodically to get an update from the OCSP responder:
+# openssl ocsp \
+#      -no_nonce \
+#      -CAfile /etc/hostapd.ca.pem \
+#      -issuer /etc/hostapd.ca.pem \
+#      -cert /etc/hostapd.server.pem \
+#      -url http://ocsp.example.com:8888/ \
+#      -respout /tmp/ocsp-cache.der
+#ocsp_stapling_response=/tmp/ocsp-cache.der
+
 # dh_file: File path to DH/DSA parameters file (in PEM format)
 # This is an optional configuration file for setting parameters for an
 # ephemeral DH key exchange. In most cases, the default RSA authentication does
@@ -844,6 +863,12 @@ own_ip_addr=127.0.0.1
 # to the bridge.
 #vlan_tagged_interface=eth0
 
+# Bridge (prefix) to add the wifi and the tagged interface to. This gets the
+# VLAN ID appended. It defaults to brvlan%d if no tagged interface is given
+# and br%s.%d if a tagged interface is given, provided %s = tagged interface
+# and %d = VLAN ID.
+#vlan_bridge=brvlan
+
 # When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
 # to know how to name it.
 # 0 = vlan<XXX>, e.g., vlan1
index 7ab86fc..fbc1ee0 100644 (file)
@@ -440,6 +440,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        os_free(conf->server_cert);
        os_free(conf->private_key);
        os_free(conf->private_key_passwd);
+       os_free(conf->ocsp_stapling_response);
        os_free(conf->dh_file);
        os_free(conf->pac_opaque_encr_key);
        os_free(conf->eap_fast_a_id);
@@ -531,6 +532,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        wpabuf_free(conf->vendor_elements);
 
        os_free(conf->sae_groups);
+
+       os_free(conf->server_id);
 }
 
 
@@ -606,11 +609,23 @@ int hostapd_rate_found(int *list, int rate)
 }
 
 
-const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id)
 {
        struct hostapd_vlan *v = vlan;
        while (v) {
                if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+                       return 1;
+               v = v->next;
+       }
+       return 0;
+}
+
+
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+{
+       struct hostapd_vlan *v = vlan;
+       while (v) {
+               if (v->vlan_id == vlan_id)
                        return v->ifname;
                v = v->next;
        }
index 7c9ea90..a744ba6 100644 (file)
@@ -180,6 +180,7 @@ struct hostapd_nai_realm_data {
 struct hostapd_bss_config {
        char iface[IFNAMSIZ + 1];
        char bridge[IFNAMSIZ + 1];
+       char vlan_bridge[IFNAMSIZ + 1];
        char wds_bridge[IFNAMSIZ + 1];
 
        enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
@@ -294,6 +295,7 @@ struct hostapd_bss_config {
        char *private_key;
        char *private_key_passwd;
        int check_crl;
+       char *ocsp_stapling_response;
        char *dh_file;
        u8 *pac_opaque_encr_key;
        u8 *eap_fast_a_id;
@@ -373,6 +375,7 @@ struct hostapd_bss_config {
        struct wpabuf *wps_nfc_dev_pw;
 #endif /* CONFIG_WPS */
        int pbc_in_m1;
+       char *server_id;
 
 #define P2P_ENABLED BIT(0)
 #define P2P_GROUP_OWNER BIT(1)
@@ -546,6 +549,7 @@ int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
 const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
                           const u8 *addr, const u8 *prev_psk);
 int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
+int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id);
 const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
                                        int vlan_id);
 struct hostapd_radius_attr *
index d66d97e..68ad4dc 100644 (file)
@@ -111,6 +111,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
        srv.eap_req_id_text = conf->eap_req_id_text;
        srv.eap_req_id_text_len = conf->eap_req_id_text_len;
        srv.pwd_group = conf->pwd_group;
+       srv.server_id = conf->server_id ? conf->server_id : "hostapd";
 #ifdef CONFIG_RADIUS_TEST
        srv.dump_msk_file = conf->dump_msk_file;
 #endif /* CONFIG_RADIUS_TEST */
@@ -148,6 +149,8 @@ int authsrv_init(struct hostapd_data *hapd)
                params.private_key = hapd->conf->private_key;
                params.private_key_passwd = hapd->conf->private_key_passwd;
                params.dh_file = hapd->conf->dh_file;
+               params.ocsp_stapling_response =
+                       hapd->conf->ocsp_stapling_response;
 
                if (tls_global_set_params(hapd->ssl_ctx, &params)) {
                        wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
index 0ef307d..2f4ba23 100644 (file)
@@ -485,6 +485,17 @@ void handle_probe_req(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_INTERWORKING */
 
+#ifdef CONFIG_P2P
+       if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+           supp_rates_11b_only(&elems)) {
+               /* Indicates support for 11b rates only */
+               wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from "
+                          MACSTR " with only 802.11b rates",
+                          MAC2STR(mgmt->sa));
+               return;
+       }
+#endif /* CONFIG_P2P */
+
        /* TODO: verify that supp_rates contains at least one matching rate
         * with AP configuration */
 
index 07fd11d..fa4b5e4 100644 (file)
@@ -85,6 +85,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
 
        sta = ap_get_sta(hapd, addr);
        if (sta) {
+               ap_sta_no_session_timeout(hapd, sta);
                accounting_sta_stop(hapd, sta);
 
                /*
index 55f6dd8..75d9c66 100644 (file)
@@ -25,6 +25,7 @@ enum wps_event;
 union wps_event_data;
 
 struct hostapd_iface;
+struct hostapd_dynamic_iface;
 
 struct hapd_interfaces {
        int (*reload_config)(struct hostapd_iface *iface);
@@ -37,11 +38,13 @@ struct hapd_interfaces {
        int (*driver_init)(struct hostapd_iface *iface);
 
        size_t count;
+       size_t count_dynamic;
        int global_ctrl_sock;
        char *global_iface_path;
        char *global_iface_name;
        gid_t ctrl_iface_group;
        struct hostapd_iface **iface;
+       struct hostapd_dynamic_iface **dynamic_iface;
 };
 
 
@@ -275,6 +278,16 @@ struct hostapd_iface {
        void (*scan_cb)(struct hostapd_iface *iface);
 };
 
+/**
+ * struct hostapd_dynamic_iface - hostapd per dynamically allocated
+ * or added interface data structure
+ */
+struct hostapd_dynamic_iface {
+       char parent[IFNAMSIZ + 1];
+       char iface[IFNAMSIZ + 1];
+       unsigned int usage;
+};
+
 /* hostapd.c */
 int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
                               int (*cb)(struct hostapd_iface *iface,
index 2e570c0..5503af1 100644 (file)
@@ -650,8 +650,7 @@ static void handle_auth(struct hostapd_data *hapd,
        }
 
        if (vlan_id > 0) {
-               if (hostapd_get_vlan_id_ifname(hapd->conf->vlan,
-                                              vlan_id) == NULL) {
+               if (!hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
                        hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
                                       HOSTAPD_LEVEL_INFO, "Invalid VLAN ID "
                                       "%d received from RADIUS server",
index a28c0f8..3554e8b 100644 (file)
@@ -1438,8 +1438,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
                        sta->vlan_id = radius_msg_get_vlanid(msg);
                }
                if (sta->vlan_id > 0 &&
-                   hostapd_get_vlan_id_ifname(hapd->conf->vlan,
-                                              sta->vlan_id)) {
+                   hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) {
                        hostapd_logger(hapd, sta->addr,
                                       HOSTAPD_MODULE_RADIUS,
                                       HOSTAPD_LEVEL_INFO,
@@ -1829,6 +1828,13 @@ int ieee802_1x_init(struct hostapd_data *hapd)
        conf.fragment_size = hapd->conf->fragment_size;
        conf.pwd_group = hapd->conf->pwd_group;
        conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
+       if (hapd->conf->server_id) {
+               conf.server_id = (const u8 *) hapd->conf->server_id;
+               conf.server_id_len = os_strlen(hapd->conf->server_id);
+       } else {
+               conf.server_id = (const u8 *) "hostapd";
+               conf.server_id_len = 7;
+       }
 
        os_memset(&cb, 0, sizeof(cb));
        cb.eapol_send = ieee802_1x_eapol_send;
index 6390e8b..70affda 100644 (file)
@@ -480,6 +480,123 @@ static int vlan_set_name_type(unsigned int name_type)
 #endif /* CONFIG_VLAN_NETLINK */
 
 
+/**
+ * Increase the usage counter for given parent/ifname combination.
+ * If create is set, then this iface is added to the global list.
+ * Returns
+ *     -1 on error
+ *     0 if iface is not in list
+ *     1 if iface is in list (was there or has been added)
+ */
+static int hapd_get_dynamic_iface(const char *parent, const char *ifname,
+                                 int create, struct hostapd_data *hapd)
+{
+       size_t i;
+       struct hostapd_dynamic_iface *j = NULL, **tmp;
+       struct hapd_interfaces *hapd_global = hapd->iface->interfaces;
+
+       if (!parent)
+               parent = "";
+
+       for (i = 0; i < hapd_global->count_dynamic; i++) {
+               j = hapd_global->dynamic_iface[i];
+               if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
+                   os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
+                       break;
+       }
+       if (i < hapd_global->count_dynamic) {
+               j->usage++;
+               return 1;
+       }
+
+       /* new entry required */
+       if (!create)
+               return 0;
+
+       j = os_zalloc(sizeof(*j));
+       if (!j)
+               return -1;
+       os_strlcpy(j->iface, ifname, sizeof(j->iface));
+       os_strlcpy(j->parent, parent, sizeof(j->parent));
+
+       tmp = os_realloc_array(hapd_global->dynamic_iface, i + 1,
+                              sizeof(*hapd_global->dynamic_iface));
+       if (!tmp) {
+               wpa_printf(MSG_ERROR, "VLAN: Failed to allocate memory in %s",
+                          __func__);
+               return -1;
+       }
+       hapd_global->count_dynamic++;
+       hapd_global->dynamic_iface = tmp;
+       hapd_global->dynamic_iface[i] = j;
+
+       return 1;
+}
+
+
+/**
+ * Decrease the usage counter for given ifname.
+ * Returns
+ *     -1 on error or if iface was not found
+ *     0 if iface was found and is still present
+ *     1 if iface was removed from global list
+ */
+static int hapd_put_dynamic_iface(const char *parent, const char *ifname,
+                                 struct hostapd_data *hapd)
+{
+       size_t i;
+       struct hostapd_dynamic_iface *j = NULL, **tmp;
+       struct hapd_interfaces *hapd_glob = hapd->iface->interfaces;
+
+       if (!parent)
+               parent = "";
+
+       for (i = 0; i < hapd_glob->count_dynamic; i++) {
+               j = hapd_glob->dynamic_iface[i];
+               if (os_strncmp(j->iface, ifname, sizeof(j->iface)) == 0 &&
+                   os_strncmp(j->parent, parent, sizeof(j->parent)) == 0)
+                       break;
+       }
+
+       if (i == hapd_glob->count_dynamic) {
+               /*
+                * Interface not in global list. This can happen if alloc in
+                * _get_ failed.
+                */
+               return -1;
+       }
+
+       if (j->usage > 0) {
+               j->usage--;
+               return 0;
+       }
+
+       os_free(j);
+       for (; i < hapd_glob->count_dynamic - 1; i++)
+               hapd_glob->dynamic_iface[i] = hapd_glob->dynamic_iface[i + 1];
+       hapd_glob->dynamic_iface[hapd_glob->count_dynamic - 1] = NULL;
+       hapd_glob->count_dynamic--;
+
+       if (hapd_glob->count_dynamic == 0) {
+               os_free(hapd_glob->dynamic_iface);
+               hapd_glob->dynamic_iface = NULL;
+               return 1;
+       }
+
+       tmp = os_realloc_array(hapd_glob->dynamic_iface,
+                              hapd_glob->count_dynamic,
+                              sizeof(*hapd_glob->dynamic_iface));
+       if (!tmp) {
+               wpa_printf(MSG_ERROR, "VLAN: Failed to release memory in %s",
+                          __func__);
+               return -1;
+       }
+       hapd_glob->dynamic_iface = tmp;
+
+       return 1;
+}
+
+
 static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
 {
        char vlan_ifname[IFNAMSIZ];
@@ -487,16 +604,29 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
        struct hostapd_vlan *vlan = hapd->conf->vlan;
        char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
        int vlan_naming = hapd->conf->ssid.vlan_naming;
+       int ret;
 
        wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
 
        while (vlan) {
                if (os_strcmp(ifname, vlan->ifname) == 0) {
 
-                       os_snprintf(br_name, sizeof(br_name), "brvlan%d",
-                                   vlan->vlan_id);
+                       if (hapd->conf->vlan_bridge[0]) {
+                               os_snprintf(br_name, sizeof(br_name), "%s%d",
+                                           hapd->conf->vlan_bridge,
+                                           vlan->vlan_id);
+                       } else if (tagged_interface) {
+                               os_snprintf(br_name, sizeof(br_name),
+                                           "br%s.%d", tagged_interface,
+                                           vlan->vlan_id);
+                       } else {
+                               os_snprintf(br_name, sizeof(br_name),
+                                           "brvlan%d", vlan->vlan_id);
+                       }
 
-                       if (!br_addbr(br_name))
+                       ret = br_addbr(br_name);
+                       if (hapd_get_dynamic_iface(NULL, br_name, ret == 0,
+                                                  hapd))
                                vlan->clean |= DVLAN_CLEAN_BR;
 
                        ifconfig_up(br_name);
@@ -514,17 +644,24 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
                                                    "vlan%d", vlan->vlan_id);
 
                                ifconfig_up(tagged_interface);
-                               if (!vlan_add(tagged_interface, vlan->vlan_id,
-                                             vlan_ifname))
+                               ret = vlan_add(tagged_interface, vlan->vlan_id,
+                                             vlan_ifname);
+                               if (hapd_get_dynamic_iface(NULL, vlan_ifname,
+                                                          ret == 0, hapd))
                                        vlan->clean |= DVLAN_CLEAN_VLAN;
 
-                               if (!br_addif(br_name, vlan_ifname))
+                               ret = br_addif(br_name, vlan_ifname);
+                               if (hapd_get_dynamic_iface(br_name,
+                                                          vlan_ifname,
+                                                          ret == 0, hapd))
                                        vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
 
                                ifconfig_up(vlan_ifname);
                        }
 
-                       if (!br_addif(br_name, ifname))
+                       ret = br_addif(br_name, ifname);
+                       if (hapd_get_dynamic_iface(br_name, ifname, ret == 0,
+                                                  hapd))
                                vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
 
                        ifconfig_up(ifname);
@@ -550,10 +687,21 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
 
        while (vlan) {
                if (os_strcmp(ifname, vlan->ifname) == 0) {
-                       os_snprintf(br_name, sizeof(br_name), "brvlan%d",
-                                   vlan->vlan_id);
+                       if (hapd->conf->vlan_bridge[0]) {
+                               os_snprintf(br_name, sizeof(br_name), "%s%d",
+                                           hapd->conf->vlan_bridge,
+                                           vlan->vlan_id);
+                       } else if (tagged_interface) {
+                               os_snprintf(br_name, sizeof(br_name),
+                                           "br%s.%d", tagged_interface,
+                                           vlan->vlan_id);
+                       } else {
+                               os_snprintf(br_name, sizeof(br_name),
+                                           "brvlan%d", vlan->vlan_id);
+                       }
 
-                       if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
+                       if ((vlan->clean & DVLAN_CLEAN_WLAN_PORT) &&
+                           hapd_put_dynamic_iface(br_name, vlan->ifname, hapd))
                                br_delif(br_name, vlan->ifname);
 
                        if (tagged_interface) {
@@ -567,15 +715,20 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
                                        os_snprintf(vlan_ifname,
                                                    sizeof(vlan_ifname),
                                                    "vlan%d", vlan->vlan_id);
-                               if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
+                               if ((vlan->clean & DVLAN_CLEAN_VLAN_PORT) &&
+                                   hapd_put_dynamic_iface(br_name, vlan_ifname,
+                                                          hapd))
                                        br_delif(br_name, vlan_ifname);
                                ifconfig_down(vlan_ifname);
 
-                               if (vlan->clean & DVLAN_CLEAN_VLAN)
+                               if ((vlan->clean & DVLAN_CLEAN_VLAN) &&
+                                   hapd_put_dynamic_iface(NULL, vlan_ifname,
+                                                          hapd))
                                        vlan_rem(vlan_ifname);
                        }
 
                        if ((vlan->clean & DVLAN_CLEAN_BR) &&
+                           hapd_put_dynamic_iface(NULL, br_name, hapd) &&
                            br_getnumports(br_name) == 0) {
                                ifconfig_down(br_name);
                                br_delbr(br_name);
index 407b066..aab8ac6 100644 (file)
@@ -512,3 +512,36 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
 
        return mode;
 }
+
+
+static int is_11b(u8 rate)
+{
+       return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
+}
+
+
+int supp_rates_11b_only(struct ieee802_11_elems *elems)
+{
+       int num_11b = 0, num_others = 0;
+       int i;
+
+       if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
+               return 0;
+
+       for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
+               if (is_11b(elems->supp_rates[i]))
+                       num_11b++;
+               else
+                       num_others++;
+       }
+
+       for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
+            i++) {
+               if (is_11b(elems->ext_supp_rates[i]))
+                       num_11b++;
+               else
+                       num_others++;
+       }
+
+       return num_11b > 0 && num_others == 0;
+}
index 7f59cf2..68c6b96 100644 (file)
@@ -101,4 +101,6 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
                          const char *name, const char *val);
 enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
 
+int supp_rates_11b_only(struct ieee802_11_elems *elems);
+
 #endif /* IEEE802_11_COMMON_H */
index a8cf6be..c3afbfd 100644 (file)
@@ -335,7 +335,6 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
 #endif /* CONFIG_IEEE80211R */
 
 
-#ifndef CONFIG_NO_WPA2
 static int rsn_selector_to_bitfield(const u8 *s)
 {
        if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
@@ -384,7 +383,6 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
 #endif /* CONFIG_SAE */
        return 0;
 }
-#endif /* CONFIG_NO_WPA2 */
 
 
 /**
@@ -397,7 +395,6 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
 int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
                         struct wpa_ie_data *data)
 {
-#ifndef CONFIG_NO_WPA2
        const struct rsn_ie_hdr *hdr;
        const u8 *pos;
        int left;
@@ -551,9 +548,6 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
        }
 
        return 0;
-#else /* CONFIG_NO_WPA2 */
-       return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
index b61e439..2fdaa02 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * SSL/TLS interface definition
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -82,6 +82,8 @@ struct tls_config {
 #define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
 #define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
 #define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
+#define TLS_CONN_REQUEST_OCSP BIT(3)
+#define TLS_CONN_REQUIRE_OCSP BIT(4)
 
 /**
  * struct tls_connection_params - Parameters for TLS connection
@@ -117,6 +119,8 @@ struct tls_config {
  * @cert_id: the certificate's id when using engine
  * @ca_cert_id: the CA certificate's id when using engine
  * @flags: Parameter options (TLS_CONN_*)
+ * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
+ *     or %NULL if OCSP is not enabled
  *
  * TLS connection parameters to be configured with tls_connection_set_params()
  * and tls_global_set_params().
@@ -153,6 +157,7 @@ struct tls_connection_params {
        const char *ca_cert_id;
 
        unsigned int flags;
+       const char *ocsp_stapling_response;
 };
 
 
index fec8e38..90acf84 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * SSL/TLS interface functions for OpenSSL
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -65,6 +65,13 @@ static BIO * BIO_from_keystore(const char *key)
 }
 #endif /* ANDROID */
 
+#ifdef SSL_set_tlsext_status_type
+#ifndef OPENSSL_NO_TLSEXT
+#define HAVE_OCSP
+#include <openssl/ocsp.h>
+#endif /* OPENSSL_NO_TLSEXT */
+#endif /* SSL_set_tlsext_status_type */
+
 static int tls_openssl_ref_count = 0;
 
 struct tls_context {
@@ -72,6 +79,7 @@ struct tls_context {
                         union tls_event_data *data);
        void *cb_ctx;
        int cert_in_cb;
+       char *ocsp_stapling_response;
 };
 
 static struct tls_context *tls_global = NULL;
@@ -102,6 +110,9 @@ struct tls_connection {
        u8 srv_cert_hash[32];
 
        unsigned int flags;
+
+       X509 *peer_cert;
+       X509 *peer_issuer;
 };
 
 
@@ -841,6 +852,8 @@ void tls_deinit(void *ssl_ctx)
                ERR_remove_state(0);
                ERR_free_strings();
                EVP_cleanup();
+               os_free(tls_global->ocsp_stapling_response);
+               tls_global->ocsp_stapling_response = NULL;
                os_free(tls_global);
                tls_global = NULL;
        }
@@ -1267,6 +1280,12 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
        conn = SSL_get_app_data(ssl);
        if (conn == NULL)
                return 0;
+
+       if (depth == 0)
+               conn->peer_cert = err_cert;
+       else if (depth == 1)
+               conn->peer_issuer = err_cert;
+
        context = conn->context;
        match = conn->subject_match;
        altmatch = conn->altsubject_match;
@@ -2768,11 +2787,187 @@ int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
 }
 
 
+#ifdef HAVE_OCSP
+
+static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+       extern int wpa_debug_level;
+       BIO *out;
+       size_t rlen;
+       char *txt;
+       int res;
+
+       if (wpa_debug_level > MSG_DEBUG)
+               return;
+
+       out = BIO_new(BIO_s_mem());
+       if (!out)
+               return;
+
+       OCSP_RESPONSE_print(out, rsp, 0);
+       rlen = BIO_ctrl_pending(out);
+       txt = os_malloc(rlen + 1);
+       if (!txt) {
+               BIO_free(out);
+               return;
+       }
+
+       res = BIO_read(out, txt, rlen);
+       if (res > 0) {
+               txt[res] = '\0';
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt);
+       }
+       os_free(txt);
+       BIO_free(out);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static int ocsp_resp_cb(SSL *s, void *arg)
+{
+       struct tls_connection *conn = arg;
+       const unsigned char *p;
+       int len, status, reason;
+       OCSP_RESPONSE *rsp;
+       OCSP_BASICRESP *basic;
+       OCSP_CERTID *id;
+       ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
+
+       len = SSL_get_tlsext_status_ocsp_resp(s, &p);
+       if (!p) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
+               return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
+
+       rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
+       if (!rsp) {
+               wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
+               return 0;
+       }
+
+       ocsp_debug_print_resp(rsp);
+
+       status = OCSP_response_status(rsp);
+       if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+               wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
+                          status, OCSP_response_status_str(status));
+               return 0;
+       }
+
+       basic = OCSP_response_get1_basic(rsp);
+       if (!basic) {
+               wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
+               return 0;
+       }
+
+       status = OCSP_basic_verify(basic, NULL, SSL_CTX_get_cert_store(s->ctx),
+                                  0);
+       if (status <= 0) {
+               tls_show_errors(MSG_INFO, __func__,
+                               "OpenSSL: OCSP response failed verification");
+               OCSP_BASICRESP_free(basic);
+               OCSP_RESPONSE_free(rsp);
+               return 0;
+       }
+
+       wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
+
+       if (!conn->peer_cert || !conn->peer_issuer) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate or issue certificate not available for OCSP status check");
+               OCSP_BASICRESP_free(basic);
+               OCSP_RESPONSE_free(rsp);
+               return 0;
+       }
+
+       id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
+       if (!id) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier");
+               OCSP_BASICRESP_free(basic);
+               OCSP_RESPONSE_free(rsp);
+               return 0;
+       }
+
+       if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
+                                  &this_update, &next_update)) {
+               wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
+                          (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
+                          " (OCSP not required)");
+               OCSP_BASICRESP_free(basic);
+               OCSP_RESPONSE_free(rsp);
+               return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
+       }
+
+       if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
+               tls_show_errors(MSG_INFO, __func__,
+                               "OpenSSL: OCSP status times invalid");
+               OCSP_BASICRESP_free(basic);
+               OCSP_RESPONSE_free(rsp);
+               return 0;
+       }
+
+       OCSP_BASICRESP_free(basic);
+       OCSP_RESPONSE_free(rsp);
+
+       wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
+                  OCSP_cert_status_str(status));
+
+       if (status == V_OCSP_CERTSTATUS_GOOD)
+               return 1;
+       if (status == V_OCSP_CERTSTATUS_REVOKED)
+               return 0;
+       if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
+               return 0;
+       }
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
+       return 1;
+}
+
+
+static int ocsp_status_cb(SSL *s, void *arg)
+{
+       char *tmp;
+       char *resp;
+       size_t len;
+
+       if (tls_global->ocsp_stapling_response == NULL) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured");
+               return SSL_TLSEXT_ERR_OK;
+       }
+
+       resp = os_readfile(tls_global->ocsp_stapling_response, &len);
+       if (resp == NULL) {
+               wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file");
+               /* TODO: Build OCSPResponse with responseStatus = internalError
+                */
+               return SSL_TLSEXT_ERR_OK;
+       }
+       wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response");
+       tmp = OPENSSL_malloc(len);
+       if (tmp == NULL) {
+               os_free(resp);
+               return SSL_TLSEXT_ERR_ALERT_FATAL;
+       }
+
+       os_memcpy(tmp, resp, len);
+       os_free(resp);
+       SSL_set_tlsext_status_ocsp_resp(s, tmp, len);
+
+       return SSL_TLSEXT_ERR_OK;
+}
+
+#endif /* HAVE_OCSP */
+
+
 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
                              const struct tls_connection_params *params)
 {
        int ret;
        unsigned long err;
+       SSL_CTX *ssl_ctx = tls_ctx;
 
        if (conn == NULL)
                return -1;
@@ -2836,10 +3031,20 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 #ifdef SSL_OP_NO_TICKET
        if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
                SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
+#ifdef SSL_clear_options
        else
                SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
+#endif /* SSL_clear_options */
 #endif /*  SSL_OP_NO_TICKET */
 
+#ifdef HAVE_OCSP
+       if (params->flags & TLS_CONN_REQUEST_OCSP) {
+               SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
+               SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
+               SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
+       }
+#endif /* HAVE_OCSP */
+
        conn->flags = params->flags;
 
        tls_get_errors(tls_ctx);
@@ -2878,10 +3083,23 @@ int tls_global_set_params(void *tls_ctx,
 #ifdef SSL_OP_NO_TICKET
        if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
                SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
+#ifdef SSL_CTX_clear_options
        else
                SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
+#endif /* SSL_clear_options */
 #endif /*  SSL_OP_NO_TICKET */
 
+#ifdef HAVE_OCSP
+       SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb);
+       SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx);
+       os_free(tls_global->ocsp_stapling_response);
+       if (params->ocsp_stapling_response)
+               tls_global->ocsp_stapling_response =
+                       os_strdup(params->ocsp_stapling_response);
+       else
+               tls_global->ocsp_stapling_response = NULL;
+#endif /* HAVE_OCSP */
+
        return 0;
 }
 
index 0f92b18..0604fef 100644 (file)
@@ -830,7 +830,7 @@ struct wpa_driver_capa {
  * it cannot be used for P2P group operations or non-P2P purposes.
  */
 #define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE       0x00000400
-/* This interface is P2P capable (P2P Device, GO, or P2P Client */
+/* This interface is P2P capable (P2P GO or P2P Client) */
 #define WPA_DRIVER_FLAGS_P2P_CAPABLE   0x00000800
 /* Driver supports concurrent operations on multiple channels */
 #define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT      0x00001000
@@ -874,6 +874,8 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS_IBSS                          0x08000000
 /* Driver supports radar detection */
 #define WPA_DRIVER_FLAGS_RADAR                         0x10000000
+/* Driver supports a dedicated interface for P2P Device */
+#define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE          0x20000000
        unsigned int flags;
 
        int max_scan_ssids;
@@ -1013,7 +1015,13 @@ enum wpa_driver_if_type {
         * WPA_IF_P2P_GROUP - P2P Group interface (will become either
         * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known)
         */
-       WPA_IF_P2P_GROUP
+       WPA_IF_P2P_GROUP,
+
+       /**
+        * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
+        * abstracted P2P Device function in the driver
+        */
+       WPA_IF_P2P_DEVICE
 };
 
 struct wpa_init_params {
@@ -1090,6 +1098,17 @@ enum wnm_oper {
        WNM_SLEEP_TFS_IE_DEL        /* AP delete the TFS IE */
 };
 
+/* enum chan_width - Channel width definitions */
+enum chan_width {
+       CHAN_WIDTH_20_NOHT,
+       CHAN_WIDTH_20,
+       CHAN_WIDTH_40,
+       CHAN_WIDTH_80,
+       CHAN_WIDTH_80P80,
+       CHAN_WIDTH_160,
+       CHAN_WIDTH_UNKNOWN
+};
+
 /**
  * struct wpa_signal_info - Information about channel signal quality
  */
@@ -1097,8 +1116,12 @@ struct wpa_signal_info {
        u32 frequency;
        int above_threshold;
        int current_signal;
+       int avg_signal;
        int current_noise;
        int current_txrate;
+       enum chan_width chanwidth;
+       int center_frq1;
+       int center_frq2;
 };
 
 /**
index cbc80e3..bcd0a94 100644 (file)
@@ -157,6 +157,8 @@ static void nl_destroy_handles(struct nl_handle **handle)
 struct nl80211_global {
        struct dl_list interfaces;
        int if_add_ifindex;
+       u64 if_add_wdevid;
+       int if_add_wdevid_set;
        struct netlink_data *netlink;
        struct nl_cb *nl_cb;
        struct nl_handle *nl;
@@ -183,12 +185,14 @@ struct i802_bss {
        struct wpa_driver_nl80211_data *drv;
        struct i802_bss *next;
        int ifindex;
+       u64 wdev_id;
        char ifname[IFNAMSIZ + 1];
        char brname[IFNAMSIZ];
        unsigned int beacon_set:1;
        unsigned int added_if_into_bridge:1;
        unsigned int added_bridge:1;
        unsigned int in_deinit:1;
+       unsigned int wdev_id_set:1;
 
        u8 addr[ETH_ALEN];
 
@@ -249,6 +253,7 @@ struct wpa_driver_nl80211_data {
        unsigned int retry_auth:1;
        unsigned int use_monitor:1;
        unsigned int ignore_next_local_disconnect:1;
+       unsigned int allow_p2p_device:1;
 
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
@@ -357,6 +362,117 @@ static int wpa_driver_nl80211_authenticate_retry(
        struct wpa_driver_nl80211_data *drv);
 
 
+static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+{
+#define C2S(x) case x: return #x;
+       switch (cmd) {
+       C2S(NL80211_CMD_UNSPEC)
+       C2S(NL80211_CMD_GET_WIPHY)
+       C2S(NL80211_CMD_SET_WIPHY)
+       C2S(NL80211_CMD_NEW_WIPHY)
+       C2S(NL80211_CMD_DEL_WIPHY)
+       C2S(NL80211_CMD_GET_INTERFACE)
+       C2S(NL80211_CMD_SET_INTERFACE)
+       C2S(NL80211_CMD_NEW_INTERFACE)
+       C2S(NL80211_CMD_DEL_INTERFACE)
+       C2S(NL80211_CMD_GET_KEY)
+       C2S(NL80211_CMD_SET_KEY)
+       C2S(NL80211_CMD_NEW_KEY)
+       C2S(NL80211_CMD_DEL_KEY)
+       C2S(NL80211_CMD_GET_BEACON)
+       C2S(NL80211_CMD_SET_BEACON)
+       C2S(NL80211_CMD_START_AP)
+       C2S(NL80211_CMD_STOP_AP)
+       C2S(NL80211_CMD_GET_STATION)
+       C2S(NL80211_CMD_SET_STATION)
+       C2S(NL80211_CMD_NEW_STATION)
+       C2S(NL80211_CMD_DEL_STATION)
+       C2S(NL80211_CMD_GET_MPATH)
+       C2S(NL80211_CMD_SET_MPATH)
+       C2S(NL80211_CMD_NEW_MPATH)
+       C2S(NL80211_CMD_DEL_MPATH)
+       C2S(NL80211_CMD_SET_BSS)
+       C2S(NL80211_CMD_SET_REG)
+       C2S(NL80211_CMD_REQ_SET_REG)
+       C2S(NL80211_CMD_GET_MESH_CONFIG)
+       C2S(NL80211_CMD_SET_MESH_CONFIG)
+       C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+       C2S(NL80211_CMD_GET_REG)
+       C2S(NL80211_CMD_GET_SCAN)
+       C2S(NL80211_CMD_TRIGGER_SCAN)
+       C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+       C2S(NL80211_CMD_SCAN_ABORTED)
+       C2S(NL80211_CMD_REG_CHANGE)
+       C2S(NL80211_CMD_AUTHENTICATE)
+       C2S(NL80211_CMD_ASSOCIATE)
+       C2S(NL80211_CMD_DEAUTHENTICATE)
+       C2S(NL80211_CMD_DISASSOCIATE)
+       C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+       C2S(NL80211_CMD_REG_BEACON_HINT)
+       C2S(NL80211_CMD_JOIN_IBSS)
+       C2S(NL80211_CMD_LEAVE_IBSS)
+       C2S(NL80211_CMD_TESTMODE)
+       C2S(NL80211_CMD_CONNECT)
+       C2S(NL80211_CMD_ROAM)
+       C2S(NL80211_CMD_DISCONNECT)
+       C2S(NL80211_CMD_SET_WIPHY_NETNS)
+       C2S(NL80211_CMD_GET_SURVEY)
+       C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+       C2S(NL80211_CMD_SET_PMKSA)
+       C2S(NL80211_CMD_DEL_PMKSA)
+       C2S(NL80211_CMD_FLUSH_PMKSA)
+       C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+       C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+       C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+       C2S(NL80211_CMD_REGISTER_FRAME)
+       C2S(NL80211_CMD_FRAME)
+       C2S(NL80211_CMD_FRAME_TX_STATUS)
+       C2S(NL80211_CMD_SET_POWER_SAVE)
+       C2S(NL80211_CMD_GET_POWER_SAVE)
+       C2S(NL80211_CMD_SET_CQM)
+       C2S(NL80211_CMD_NOTIFY_CQM)
+       C2S(NL80211_CMD_SET_CHANNEL)
+       C2S(NL80211_CMD_SET_WDS_PEER)
+       C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+       C2S(NL80211_CMD_JOIN_MESH)
+       C2S(NL80211_CMD_LEAVE_MESH)
+       C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+       C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+       C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+       C2S(NL80211_CMD_GET_WOWLAN)
+       C2S(NL80211_CMD_SET_WOWLAN)
+       C2S(NL80211_CMD_START_SCHED_SCAN)
+       C2S(NL80211_CMD_STOP_SCHED_SCAN)
+       C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+       C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+       C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+       C2S(NL80211_CMD_PMKSA_CANDIDATE)
+       C2S(NL80211_CMD_TDLS_OPER)
+       C2S(NL80211_CMD_TDLS_MGMT)
+       C2S(NL80211_CMD_UNEXPECTED_FRAME)
+       C2S(NL80211_CMD_PROBE_CLIENT)
+       C2S(NL80211_CMD_REGISTER_BEACONS)
+       C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+       C2S(NL80211_CMD_SET_NOACK_MAP)
+       C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+       C2S(NL80211_CMD_START_P2P_DEVICE)
+       C2S(NL80211_CMD_STOP_P2P_DEVICE)
+       C2S(NL80211_CMD_CONN_FAILED)
+       C2S(NL80211_CMD_SET_MCAST_RATE)
+       C2S(NL80211_CMD_SET_MAC_ACL)
+       C2S(NL80211_CMD_RADAR_DETECT)
+       C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+       C2S(NL80211_CMD_UPDATE_FT_IES)
+       C2S(NL80211_CMD_FT_EVENT)
+       C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+       C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+       default:
+               return "NL80211_CMD_UNKNOWN";
+       }
+#undef C2S
+}
+
+
 static int is_ap_interface(enum nl80211_iftype nlmode)
 {
        return (nlmode == NL80211_IFTYPE_AP ||
@@ -371,7 +487,7 @@ static int is_sta_interface(enum nl80211_iftype nlmode)
 }
 
 
-static int is_p2p_interface(enum nl80211_iftype nlmode)
+static int is_p2p_net_interface(enum nl80211_iftype nlmode)
 {
        return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
                nlmode == NL80211_IFTYPE_P2P_GO);
@@ -491,6 +607,19 @@ struct family_data {
 };
 
 
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+       if (bss->wdev_id_set)
+               NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+       else
+               NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       return 0;
+
+nla_put_failure:
+       return -1;
+}
+
+
 static int family_handler(struct nl_msg *msg, void *arg)
 {
        struct family_data *res = arg;
@@ -557,6 +686,8 @@ static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
 
 struct wiphy_idx_data {
        int wiphy_idx;
+       enum nl80211_iftype nlmode;
+       u8 *macaddr;
 };
 
 
@@ -572,6 +703,13 @@ static int netdev_info_handler(struct nl_msg *msg, void *arg)
        if (tb[NL80211_ATTR_WIPHY])
                info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
 
+       if (tb[NL80211_ATTR_IFTYPE])
+               info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
+
+       if (tb[NL80211_ATTR_MAC] && info->macaddr)
+               os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+                         ETH_ALEN);
+
        return NL_SKIP;
 }
 
@@ -581,15 +719,17 @@ static int nl80211_get_wiphy_index(struct i802_bss *bss)
        struct nl_msg *msg;
        struct wiphy_idx_data data = {
                .wiphy_idx = -1,
+               .macaddr = NULL,
        };
 
        msg = nlmsg_alloc();
        if (!msg)
-               return -1;
+               return NL80211_IFTYPE_UNSPECIFIED;
 
        nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
 
        if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
                return data.wiphy_idx;
@@ -600,6 +740,57 @@ nla_put_failure:
 }
 
 
+static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
+{
+       struct nl_msg *msg;
+       struct wiphy_idx_data data = {
+               .nlmode = NL80211_IFTYPE_UNSPECIFIED,
+               .macaddr = NULL,
+       };
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
+       if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+               return data.nlmode;
+       msg = NULL;
+nla_put_failure:
+       nlmsg_free(msg);
+       return NL80211_IFTYPE_UNSPECIFIED;
+}
+
+
+#ifndef HOSTAPD
+static int nl80211_get_macaddr(struct i802_bss *bss)
+{
+       struct nl_msg *msg;
+       struct wiphy_idx_data data = {
+               .macaddr = bss->addr,
+       };
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return NL80211_IFTYPE_UNSPECIFIED;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
+       return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return NL80211_IFTYPE_UNSPECIFIED;
+}
+#endif /* HOSTAPD */
+
+
 static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
                                    struct nl80211_wiphy_data *w)
 {
@@ -1532,22 +1723,26 @@ static void mlme_event(struct i802_bss *bss,
        }
 
        if (frame == NULL) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
-                          "data", cmd);
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: MLME event %d (%s) without frame data",
+                          cmd, nl80211_command_to_string(cmd));
                return;
        }
 
        data = nla_data(frame);
        len = nla_len(frame);
        if (len < 4 + 2 * ETH_ALEN) {
-               wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d on %s(" MACSTR
-                          ") - too short",
-                          cmd, bss->ifname, MAC2STR(bss->addr));
+               wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
+                          MACSTR ") - too short",
+                          cmd, nl80211_command_to_string(cmd), bss->ifname,
+                          MAC2STR(bss->addr));
                return;
        }
-       wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d on %s(" MACSTR ") A1="
-                  MACSTR " A2=" MACSTR, cmd, bss->ifname, MAC2STR(bss->addr),
-                  MAC2STR(data + 4), MAC2STR(data + 4 + ETH_ALEN));
+       wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
+                  ") A1=" MACSTR " A2=" MACSTR, cmd,
+                  nl80211_command_to_string(cmd), bss->ifname,
+                  MAC2STR(bss->addr), MAC2STR(data + 4),
+                  MAC2STR(data + 4 + ETH_ALEN));
        if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
            os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
            os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
@@ -1780,6 +1975,7 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
        struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
        static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
                [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+               [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
        };
        struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
        static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -1802,6 +1998,12 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
        sig_change->current_signal =
                (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
 
+       if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
+               sig_change->avg_signal =
+                       (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
+       else
+               sig_change->avg_signal = 0;
+
        if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
                if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
                                     sinfo[NL80211_STA_INFO_TX_BITRATE],
@@ -2341,6 +2543,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
+                  cmd, nl80211_command_to_string(cmd), bss->ifname);
+
        if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
            (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
             cmd == NL80211_CMD_SCAN_ABORTED)) {
@@ -2484,19 +2689,31 @@ static int process_drv_event(struct nl_msg *msg, void *arg)
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
-       if (tb[NL80211_ATTR_IFINDEX])
+       if (tb[NL80211_ATTR_IFINDEX]) {
                ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
-       for (bss = &drv->first_bss; bss; bss = bss->next) {
-               if (ifidx == -1 || ifidx == bss->ifindex) {
-                       do_process_drv_event(bss, gnlh->cmd, tb);
-                       return NL_SKIP;
+               for (bss = &drv->first_bss; bss; bss = bss->next)
+                       if (ifidx == -1 || ifidx == bss->ifindex) {
+                               do_process_drv_event(bss, gnlh->cmd, tb);
+                               return NL_SKIP;
+                       }
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)",
+                          gnlh->cmd, ifidx);
+       } else if (tb[NL80211_ATTR_WDEV]) {
+               u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
+               for (bss = &drv->first_bss; bss; bss = bss->next) {
+                       if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
+                               do_process_drv_event(bss, gnlh->cmd, tb);
+                               return NL_SKIP;
+                       }
                }
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)",
+                          gnlh->cmd, (long long unsigned int) wdev_id);
        }
 
-       wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d) for foreign "
-                  "interface (ifindex %d)", gnlh->cmd, ifidx);
-
        return NL_SKIP;
 }
 
@@ -2509,17 +2726,26 @@ static int process_global_event(struct nl_msg *msg, void *arg)
        struct wpa_driver_nl80211_data *drv, *tmp;
        int ifidx = -1;
        struct i802_bss *bss;
+       u64 wdev_id = 0;
+       int wdev_id_set = 0;
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
        if (tb[NL80211_ATTR_IFINDEX])
                ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+       else if (tb[NL80211_ATTR_WDEV]) {
+               wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wdev_id_set = 1;
+       }
 
        dl_list_for_each_safe(drv, tmp, &global->interfaces,
                              struct wpa_driver_nl80211_data, list) {
                for (bss = &drv->first_bss; bss; bss = bss->next) {
-                       if (ifidx == -1 || ifidx == bss->ifindex) {
+                       if ((ifidx == -1 && !wdev_id_set) ||
+                           ifidx == bss->ifindex ||
+                           (wdev_id_set && bss->wdev_id_set &&
+                            wdev_id == bss->wdev_id)) {
                                do_process_drv_event(bss, gnlh->cmd, tb);
                                return NL_SKIP;
                        }
@@ -2539,6 +2765,10 @@ static int process_bss_event(struct nl_msg *msg, void *arg)
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
+       wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
+                  gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+                  bss->ifname);
+
        switch (gnlh->cmd) {
        case NL80211_CMD_FRAME:
        case NL80211_CMD_FRAME_TX_STATUS:
@@ -2699,6 +2929,10 @@ static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
                case NL80211_IFTYPE_ADHOC:
                        info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
                        break;
+               case NL80211_IFTYPE_P2P_DEVICE:
+                       info->capa->flags |=
+                               WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+                       break;
                case NL80211_IFTYPE_P2P_GO:
                        info->p2p_go_supported = 1;
                        break;
@@ -2896,6 +3130,10 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
+       if (tb[NL80211_ATTR_WIPHY_NAME])
+               os_strncpy(drv->phyname,
+                          nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
+                          sizeof(drv->phyname));
        if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
                capa->max_scan_ssids =
                        nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
@@ -2992,7 +3230,8 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
                nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
        NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
+       if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+               goto nla_put_failure;
 
        if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
                return -1;
@@ -3265,39 +3504,6 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
 }
 
 
-static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
-{
-       /* Find phy (radio) to which this interface belongs */
-       char buf[90], *pos;
-       int f, rv;
-
-       drv->phyname[0] = '\0';
-       snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
-                drv->first_bss.ifname);
-       f = open(buf, O_RDONLY);
-       if (f < 0) {
-               wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
-                          buf, strerror(errno));
-               return;
-       }
-
-       rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
-       close(f);
-       if (rv < 0) {
-               wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
-                          buf, strerror(errno));
-               return;
-       }
-
-       drv->phyname[rv] = '\0';
-       pos = os_strchr(drv->phyname, '\n');
-       if (pos)
-               *pos = '\0';
-       wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
-                  drv->first_bss.ifname, drv->phyname);
-}
-
-
 static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
                                                      void *eloop_ctx,
                                                      void *handle)
@@ -3419,8 +3625,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
        if (nl80211_init_bss(bss))
                goto failed;
 
-       nl80211_get_phy_name(drv);
-
        rcfg = os_zalloc(sizeof(*rcfg));
        if (rcfg == NULL)
                goto failed;
@@ -3491,7 +3695,9 @@ static int nl80211_register_frame(struct i802_bss *bss,
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
        NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
        NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
@@ -3728,27 +3934,124 @@ static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+static void nl80211_del_p2pdev(struct i802_bss *bss)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
+       NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
+                  bss->ifname, (long long unsigned int) bss->wdev_id,
+                  strerror(ret));
+
+nla_put_failure:
+       nlmsg_free(msg);
+}
+
+
+static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret = -1;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       if (start)
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_START_P2P_DEVICE);
+       else
+               nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_P2P_DEVICE);
+
+       NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+
+       wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
+                  start ? "Start" : "Stop",
+                  bss->ifname, (long long unsigned int) bss->wdev_id,
+                  strerror(ret));
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return ret;
+}
+
+
+static int i802_set_iface_flags(struct i802_bss *bss, int up)
+{
+       enum nl80211_iftype nlmode;
+
+       nlmode = nl80211_get_ifmode(bss);
+       if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+               return linux_set_iface_flags(bss->drv->global->ioctl_sock,
+                                            bss->ifname, up);
+       }
+
+       /* P2P Device has start/stop which is equivalent */
+       return nl80211_set_p2pdev(bss, up);
+}
+
+
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
 {
+#ifndef HOSTAPD
+       enum nl80211_iftype nlmode = NL80211_IFTYPE_STATION;
+#endif /* HOSTAPD */
        struct i802_bss *bss = &drv->first_bss;
        int send_rfkill_event = 0;
+       int dynamic_if;
 
        drv->ifindex = if_nametoindex(bss->ifname);
-       drv->first_bss.ifindex = drv->ifindex;
+       bss->ifindex = drv->ifindex;
+       bss->wdev_id = drv->global->if_add_wdevid;
+       bss->wdev_id_set = drv->global->if_add_wdevid_set;
+
+       dynamic_if = drv->ifindex == drv->global->if_add_ifindex;
+       dynamic_if = dynamic_if || drv->global->if_add_wdevid_set;
+       drv->global->if_add_wdevid_set = 0;
+
+       if (wpa_driver_nl80211_capa(drv))
+               return -1;
+
+       wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
+                  bss->ifname, drv->phyname);
 
 #ifndef HOSTAPD
+       if (dynamic_if)
+               nlmode = nl80211_get_ifmode(bss);
+
        /*
         * Make sure the interface starts up in station mode unless this is a
         * dynamically added interface (e.g., P2P) that was already configured
         * with proper iftype.
         */
-       if (drv->ifindex != drv->global->if_add_ifindex &&
-           wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
-               wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
-                          "use managed mode");
+       if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
+               wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to use managed mode");
                return -1;
        }
+       drv->nlmode = nlmode;
+
+       if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+               int ret = nl80211_set_p2pdev(bss, 1);
+               if (ret < 0)
+                       wpa_printf(MSG_ERROR, "nl80211: Could not start P2P device");
+               nl80211_get_macaddr(bss);
+               return ret;
+       }
 
        if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
                if (rfkill_is_blocked(drv->rfkill)) {
@@ -3768,9 +4071,6 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
                               1, IF_OPER_DORMANT);
 #endif /* HOSTAPD */
 
-       if (wpa_driver_nl80211_capa(drv))
-               return -1;
-
        if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
                               bss->addr))
                return -1;
@@ -3867,10 +4167,13 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 
        eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-       (void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
-       wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
-       nl80211_mgmt_unsubscribe(bss, "deinit");
-
+       (void) i802_set_iface_flags(bss, 0);
+       if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+               wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+       } else {
+               nl80211_mgmt_unsubscribe(bss, "deinit");
+               nl80211_del_p2pdev(bss);
+       }
        nl_cb_put(drv->nl_cb);
 
        nl80211_destroy_bss(&drv->first_bss);
@@ -3911,7 +4214,7 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 
 static struct nl_msg *
 nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
-                   struct wpa_driver_scan_params *params)
+                   struct wpa_driver_scan_params *params, u64 *wdev_id)
 {
        struct nl_msg *msg;
        size_t i;
@@ -3922,8 +4225,10 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
 
        nl80211_cmd(drv, msg, 0, cmd);
 
-       if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
-               goto fail;
+       if (!wdev_id)
+               NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       else
+               NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);
 
        if (params->num_ssids) {
                struct nlattr *ssids;
@@ -3972,6 +4277,7 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
        return msg;
 
 fail:
+nla_put_failure:
        nlmsg_free(msg);
        return NULL;
 }
@@ -3993,7 +4299,8 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
        wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
        drv->scan_for_auth = 0;
 
-       msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params);
+       msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
+                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
        if (!msg)
                return -1;
 
@@ -4096,7 +4403,8 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
                return android_pno_start(bss, params);
 #endif /* ANDROID */
 
-       msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
+       msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
+                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
        if (!msg)
                goto nla_put_failure;
 
@@ -4499,7 +4807,8 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
                goto nla_put_failure;
 
        nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+               goto nla_put_failure;
 
        arg.drv = drv;
        arg.res = res;
@@ -4570,13 +4879,18 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                                      const u8 *key, size_t key_len)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       int ifindex = if_nametoindex(ifname);
+       int ifindex;
        struct nl_msg *msg;
        int ret;
 
-       wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
+       /* Ignore for P2P Device */
+       if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+               return 0;
+
+       ifindex = if_nametoindex(ifname);
+       wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
                   "set_tx=%d seq_len=%lu key_len=%lu",
-                  __func__, ifindex, alg, addr, key_idx, set_tx,
+                  __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
                   (unsigned long) seq_len, (unsigned long) key_len);
 #ifdef CONFIG_TDLS
        if (key_idx == -1)
@@ -5785,7 +6099,8 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
        mgmt = (struct ieee80211_mgmt *) data;
        fc = le_to_host16(mgmt->frame_control);
 
-       if (is_sta_interface(drv->nlmode) &&
+       if ((is_sta_interface(drv->nlmode) ||
+            drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
            WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
            WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
                /*
@@ -6406,6 +6721,8 @@ static const char * nl80211_iftype_str(enum nl80211_iftype mode)
                return "P2P_CLIENT";
        case NL80211_IFTYPE_P2P_GO:
                return "P2P_GO";
+       case NL80211_IFTYPE_P2P_DEVICE:
+               return "P2P_DEVICE";
        default:
                return "unknown";
        }
@@ -6415,7 +6732,9 @@ static const char * nl80211_iftype_str(enum nl80211_iftype mode)
 static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                                     const char *ifname,
                                     enum nl80211_iftype iftype,
-                                    const u8 *addr, int wds)
+                                    const u8 *addr, int wds,
+                                    int (*handler)(struct nl_msg *, void *),
+                                    void *arg)
 {
        struct nl_msg *msg;
        int ifidx;
@@ -6429,7 +6748,8 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                return -1;
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+               goto nla_put_failure;
        NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
        NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
 
@@ -6447,7 +6767,7 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
        }
 
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, handler, arg);
        msg = NULL;
        if (ret) {
  nla_put_failure:
@@ -6457,6 +6777,9 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                return ret;
        }
 
+       if (iftype == NL80211_IFTYPE_P2P_DEVICE)
+               return 0;
+
        ifidx = if_nametoindex(ifname);
        wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
                   ifname, ifidx);
@@ -6479,11 +6802,14 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 
 static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
                                const char *ifname, enum nl80211_iftype iftype,
-                               const u8 *addr, int wds)
+                               const u8 *addr, int wds,
+                               int (*handler)(struct nl_msg *, void *),
+                               void *arg)
 {
        int ret;
 
-       ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
+       ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
+                                       arg);
 
        /* if error occurred and interface exists already */
        if (ret == -ENFILE && if_nametoindex(ifname)) {
@@ -6494,10 +6820,10 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 
                /* Try to create the interface again */
                ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
-                                               wds);
+                                               wds, handler, arg);
        }
 
-       if (ret >= 0 && is_p2p_interface(iftype))
+       if (ret >= 0 && is_p2p_net_interface(iftype))
                nl80211_disable_11b_rates(drv, ret, 1);
 
        return ret;
@@ -6844,7 +7170,7 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
 
        drv->monitor_ifidx =
                nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-                                    0);
+                                    0, NULL, NULL);
 
        if (drv->monitor_ifidx == -EOPNOTSUPP) {
                /*
@@ -7707,7 +8033,8 @@ static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
                return -ENOMEM;
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+       if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
+               goto nla_put_failure;
        NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7732,6 +8059,9 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
        int res;
 
        res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+       if (res && nlmode == nl80211_get_ifmode(bss))
+               res = 0;
+
        if (res == 0) {
                drv->nlmode = nlmode;
                ret = 0;
@@ -7755,8 +8085,7 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
        wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
                   "interface down");
        for (i = 0; i < 10; i++) {
-               res = linux_set_iface_flags(drv->global->ioctl_sock,
-                                           bss->ifname, 0);
+               res = i802_set_iface_flags(bss, 0);
                if (res == -EACCES || res == -ENODEV)
                        break;
                if (res == 0) {
@@ -7765,8 +8094,7 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
                        ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
                        if (ret == -EACCES)
                                break;
-                       res = linux_set_iface_flags(drv->global->ioctl_sock,
-                                                   bss->ifname, 1);
+                       res = i802_set_iface_flags(bss, 1);
                        if (res && !ret)
                                ret = -1;
                        else if (ret != -EBUSY)
@@ -7791,7 +8119,7 @@ done:
                return ret;
        }
 
-       if (is_p2p_interface(nlmode))
+       if (is_p2p_net_interface(nlmode))
                nl80211_disable_11b_rates(drv, drv->ifindex, 1);
        else if (drv->disabled_11b_rates)
                nl80211_disable_11b_rates(drv, drv->ifindex, 0);
@@ -7830,6 +8158,13 @@ static int wpa_driver_nl80211_get_capa(void *priv,
                capa->extended_capa_mask = drv->extended_capa_mask;
                capa->extended_capa_len = drv->extended_capa_len;
        }
+
+       if ((capa->flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+           !drv->allow_p2p_device) {
+               wpa_printf(MSG_DEBUG, "nl80211: Do not indicate P2P_DEVICE support (p2p_device=1 driver param not specified)");
+               capa->flags &= ~WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+       }
+
        return 0;
 }
 
@@ -8368,7 +8703,7 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
                if (!if_nametoindex(name)) {
                        if (nl80211_create_iface(drv, name,
                                                 NL80211_IFTYPE_AP_VLAN,
-                                                bss->addr, 1) < 0)
+                                                bss->addr, 1, NULL, NULL) < 0)
                                return -1;
                        if (bridge_ifname &&
                            linux_br_add_if(drv->global->ioctl_sock,
@@ -8584,6 +8919,8 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
                return NL80211_IFTYPE_AP;
        case WPA_IF_P2P_GO:
                return NL80211_IFTYPE_P2P_GO;
+       case WPA_IF_P2P_DEVICE:
+               return NL80211_IFTYPE_P2P_DEVICE;
        }
        return -1;
 }
@@ -8630,12 +8967,40 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
 #endif /* CONFIG_P2P */
 
 
+struct wdev_info {
+       u64 wdev_id;
+       int wdev_id_set;
+       u8 macaddr[ETH_ALEN];
+};
+
+static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
+{
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct wdev_info *wi = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+       if (tb[NL80211_ATTR_WDEV]) {
+               wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wi->wdev_id_set = 1;
+       }
+
+       if (tb[NL80211_ATTR_MAC])
+               os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+                         ETH_ALEN);
+
+       return NL_SKIP;
+}
+
+
 static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                                     const char *ifname, const u8 *addr,
                                     void *bss_ctx, void **drv_priv,
                                     char *force_ifname, u8 *if_addr,
                                     const char *bridge)
 {
+       enum nl80211_iftype nlmode;
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifidx;
@@ -8651,21 +9016,46 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
 
        if (addr)
                os_memcpy(if_addr, addr, ETH_ALEN);
-       ifidx = nl80211_create_iface(drv, ifname,
-                                    wpa_driver_nl80211_if_type(type), addr,
-                                    0);
-       if (ifidx < 0) {
+       nlmode = wpa_driver_nl80211_if_type(type);
+       if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+               struct wdev_info p2pdev_info;
+
+               os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
+               ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+                                            0, nl80211_wdev_handler,
+                                            &p2pdev_info);
+               if (!p2pdev_info.wdev_id_set || ifidx != 0) {
+                       wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
+                                  ifname);
+                       return -1;
+               }
+
+               drv->global->if_add_wdevid = p2pdev_info.wdev_id;
+               drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
+               if (!is_zero_ether_addr(p2pdev_info.macaddr))
+                       os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
+               wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
+                          ifname,
+                          (long long unsigned int) p2pdev_info.wdev_id);
+       } else {
+               ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
+                                            0, NULL, NULL);
+               if (ifidx < 0) {
 #ifdef HOSTAPD
-               os_free(new_bss);
+                       os_free(new_bss);
 #endif /* HOSTAPD */
-               return -1;
+                       return -1;
+               }
        }
 
-       if (!addr &&
-           linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                              if_addr) < 0) {
-               nl80211_remove_iface(drv, ifidx);
-               return -1;
+       if (!addr) {
+               if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+                       os_memcpy(if_addr, bss->addr, ETH_ALEN);
+               else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
+                                           bss->ifname, if_addr) < 0) {
+                       nl80211_remove_iface(drv, ifidx);
+                       return -1;
+               }
        }
 
 #ifdef CONFIG_P2P
@@ -8673,16 +9063,14 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
            (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
             type == WPA_IF_P2P_GO)) {
                /* Enforce unique P2P Interface Address */
-               u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
+               u8 new_addr[ETH_ALEN];
 
-               if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                                      own_addr) < 0 ||
-                   linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+               if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
                                       new_addr) < 0) {
                        nl80211_remove_iface(drv, ifidx);
                        return -1;
                }
-               if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) {
+               if (nl80211_addr_in_use(drv->global, new_addr)) {
                        wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
                                   "for P2P group interface");
                        if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
@@ -8830,7 +9218,9 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
                   freq, wait, no_cck, no_ack, offchanok);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        if (wait)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
@@ -8923,7 +9313,8 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
                   (long long unsigned int) drv->send_action_cookie);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -8952,7 +9343,9 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
 
@@ -8999,7 +9392,9 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss) < 0)
+               goto nla_put_failure;
+
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -9154,11 +9549,9 @@ static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
 static void wpa_driver_nl80211_resume(void *priv)
 {
        struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
-               wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
-                          "resume event");
-       }
+
+       if (i802_set_iface_flags(bss, 1))
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
 }
 
 
@@ -9245,6 +9638,75 @@ nla_put_failure:
 }
 
 
+/* Converts nl80211_chan_width to a common format */
+static enum chan_width convert2width(int width)
+{
+       switch (width) {
+       case NL80211_CHAN_WIDTH_20_NOHT:
+               return CHAN_WIDTH_20_NOHT;
+       case NL80211_CHAN_WIDTH_20:
+               return CHAN_WIDTH_20;
+       case NL80211_CHAN_WIDTH_40:
+               return CHAN_WIDTH_40;
+       case NL80211_CHAN_WIDTH_80:
+               return CHAN_WIDTH_80;
+       case NL80211_CHAN_WIDTH_80P80:
+               return CHAN_WIDTH_80P80;
+       case NL80211_CHAN_WIDTH_160:
+               return CHAN_WIDTH_160;
+       }
+       return CHAN_WIDTH_UNKNOWN;
+}
+
+
+static int get_channel_width(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct wpa_signal_info *sig_change = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       sig_change->center_frq1 = -1;
+       sig_change->center_frq2 = -1;
+       sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+       if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+               sig_change->chanwidth = convert2width(
+                       nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+               if (tb[NL80211_ATTR_CENTER_FREQ1])
+                       sig_change->center_frq1 =
+                               nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+               if (tb[NL80211_ATTR_CENTER_FREQ2])
+                       sig_change->center_frq2 =
+                               nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+       }
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
+                                    struct wpa_signal_info *sig)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       return send_and_recv_msgs(drv, msg, get_channel_width, sig);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
 static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
 {
        struct i802_bss *bss = priv;
@@ -9256,6 +9718,10 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
        if (res != 0)
                return res;
 
+       res = nl80211_get_channel_width(drv, si);
+       if (res != 0)
+               return res;
+
        return nl80211_get_link_noise(drv, si);
 }
 
@@ -9330,6 +9796,13 @@ static int nl80211_set_param(void *priv, const char *param)
                drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
                drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
        }
+
+       if (os_strstr(param, "p2p_device=1")) {
+               struct i802_bss *bss = priv;
+               struct wpa_driver_nl80211_data *drv = bss->drv;
+               drv->allow_p2p_device = 1;
+       }
+
 #ifdef ANDROID_P2P
        if(os_strstr(param, "use_multi_chan_concurrent=1")) {
                struct i802_bss *bss = priv;
@@ -10013,6 +10486,18 @@ nla_put_failure:
 }
 
 
+const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
+               return NULL;
+
+       return bss->addr;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -10092,6 +10577,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .tdls_oper = nl80211_tdls_oper,
 #endif /* CONFIG_TDLS */
        .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
+       .get_mac_addr = wpa_driver_nl80211_get_macaddr,
 #ifdef ANDROID_P2P
        .set_noa = wpa_driver_set_p2p_noa,
        .get_noa = wpa_driver_get_p2p_noa,
index 0d247c4..f5890be 100644 (file)
@@ -63,6 +63,7 @@ typedef enum {
        EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */,
        EAP_TYPE_GPSK = 51 /* RFC 5433 */,
        EAP_TYPE_PWD = 52 /* RFC 5931 */,
+       EAP_TYPE_EKE = 53 /* RFC 6124 */,
        EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
 } EapType;
 
diff --git a/src/eap_common/eap_eke_common.c b/src/eap_common/eap_eke_common.c
new file mode 100644 (file)
index 0000000..a62ac8e
--- /dev/null
@@ -0,0 +1,768 @@
+/*
+ * EAP server/peer: EAP-EKE shared routines
+ * Copyright (c) 2011-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/aes.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/dh_groups.h"
+#include "crypto/random.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "eap_common/eap_defs.h"
+#include "eap_eke_common.h"
+
+
+static int eap_eke_dh_len(u8 group)
+{
+       switch (group) {
+       case EAP_EKE_DHGROUP_EKE_2:
+               return 128;
+       case EAP_EKE_DHGROUP_EKE_5:
+               return 192;
+       case EAP_EKE_DHGROUP_EKE_14:
+               return 256;
+       case EAP_EKE_DHGROUP_EKE_15:
+               return 384;
+       case EAP_EKE_DHGROUP_EKE_16:
+               return 512;
+       }
+
+       return -1;
+}
+
+
+static int eap_eke_dhcomp_len(u8 dhgroup, u8 encr)
+{
+       int dhlen;
+
+       dhlen = eap_eke_dh_len(dhgroup);
+       if (dhlen < 0)
+               return -1;
+       if (encr != EAP_EKE_ENCR_AES128_CBC)
+               return -1;
+       return AES_BLOCK_SIZE + dhlen;
+}
+
+
+static const struct dh_group * eap_eke_dh_group(u8 group)
+{
+       switch (group) {
+       case EAP_EKE_DHGROUP_EKE_2:
+               return dh_groups_get(2);
+       case EAP_EKE_DHGROUP_EKE_5:
+               return dh_groups_get(5);
+       case EAP_EKE_DHGROUP_EKE_14:
+               return dh_groups_get(14);
+       case EAP_EKE_DHGROUP_EKE_15:
+               return dh_groups_get(15);
+       case EAP_EKE_DHGROUP_EKE_16:
+               return dh_groups_get(16);
+       }
+
+       return NULL;
+}
+
+
+static int eap_eke_dh_generator(u8 group)
+{
+       switch (group) {
+       case EAP_EKE_DHGROUP_EKE_2:
+               return 5;
+       case EAP_EKE_DHGROUP_EKE_5:
+               return 31;
+       case EAP_EKE_DHGROUP_EKE_14:
+               return 11;
+       case EAP_EKE_DHGROUP_EKE_15:
+               return 5;
+       case EAP_EKE_DHGROUP_EKE_16:
+               return 5;
+       }
+
+       return -1;
+}
+
+
+static int eap_eke_pnonce_len(u8 mac)
+{
+       int mac_len;
+
+       if (mac == EAP_EKE_MAC_HMAC_SHA1)
+               mac_len = SHA1_MAC_LEN;
+       else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+               mac_len = SHA256_MAC_LEN;
+       else
+               return -1;
+
+       return AES_BLOCK_SIZE + 16 + mac_len;
+}
+
+
+static int eap_eke_pnonce_ps_len(u8 mac)
+{
+       int mac_len;
+
+       if (mac == EAP_EKE_MAC_HMAC_SHA1)
+               mac_len = SHA1_MAC_LEN;
+       else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+               mac_len = SHA256_MAC_LEN;
+       else
+               return -1;
+
+       return AES_BLOCK_SIZE + 2 * 16 + mac_len;
+}
+
+
+static int eap_eke_prf_len(u8 prf)
+{
+       if (prf == EAP_EKE_PRF_HMAC_SHA1)
+               return 20;
+       if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+               return 32;
+       return -1;
+}
+
+
+static int eap_eke_nonce_len(u8 prf)
+{
+       int prf_len;
+
+       prf_len = eap_eke_prf_len(prf);
+       if (prf_len < 0)
+               return -1;
+
+       if (prf_len > 2 * 16)
+               return (prf_len + 1) / 2;
+
+       return 16;
+}
+
+
+static int eap_eke_auth_len(u8 prf)
+{
+       switch (prf) {
+       case EAP_EKE_PRF_HMAC_SHA1:
+               return SHA1_MAC_LEN;
+       case EAP_EKE_PRF_HMAC_SHA2_256:
+               return SHA256_MAC_LEN;
+       }
+
+       return -1;
+}
+
+
+int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub)
+{
+       int generator;
+       u8 gen;
+       const struct dh_group *dh;
+       size_t pub_len, i;
+
+       generator = eap_eke_dh_generator(group);
+       if (generator < 0 || generator > 255)
+               return -1;
+       gen = generator;
+
+       dh = eap_eke_dh_group(group);
+       if (dh == NULL)
+               return -1;
+
+       /* x = random number 2 .. p-1 */
+       if (random_get_bytes(ret_priv, dh->prime_len))
+               return -1;
+       if (os_memcmp(ret_priv, dh->prime, dh->prime_len) > 0) {
+               /* Make sure private value is smaller than prime */
+               ret_priv[0] = 0;
+       }
+       for (i = 0; i < dh->prime_len - 1; i++) {
+               if (ret_priv[i])
+                       break;
+       }
+       if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1))
+               return -1;
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
+                       ret_priv, dh->prime_len);
+
+       /* y = g ^ x (mod p) */
+       pub_len = dh->prime_len;
+       if (crypto_mod_exp(&gen, 1, ret_priv, dh->prime_len,
+                          dh->prime, dh->prime_len, ret_pub, &pub_len) < 0)
+               return -1;
+       if (pub_len < dh->prime_len) {
+               size_t pad = dh->prime_len - pub_len;
+               os_memmove(ret_pub + pad, ret_pub, pub_len);
+               os_memset(ret_pub, 0, pad);
+       }
+
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
+                   ret_pub, dh->prime_len);
+
+       return 0;
+}
+
+
+static int eap_eke_prf(u8 prf, const u8 *key, size_t key_len, const u8 *data,
+                      size_t data_len, const u8 *data2, size_t data2_len,
+                      u8 *res)
+{
+       const u8 *addr[2];
+       size_t len[2];
+       size_t num_elem = 1;
+
+       addr[0] = data;
+       len[0] = data_len;
+       if (data2) {
+               num_elem++;
+               addr[1] = data2;
+               len[1] = data2_len;
+       }
+
+       if (prf == EAP_EKE_PRF_HMAC_SHA1)
+               return hmac_sha1_vector(key, key_len, num_elem, addr, len, res);
+       if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+               return hmac_sha256_vector(key, key_len, num_elem, addr, len,
+                                         res);
+       return -1;
+}
+
+
+static int eap_eke_prf_hmac_sha1(const u8 *key, size_t key_len, const u8 *data,
+                                size_t data_len, u8 *res, size_t len)
+{
+       u8 hash[SHA1_MAC_LEN];
+       u8 idx;
+       const u8 *addr[3];
+       size_t vlen[3];
+       int ret;
+
+       idx = 0;
+       addr[0] = hash;
+       vlen[0] = SHA1_MAC_LEN;
+       addr[1] = data;
+       vlen[1] = data_len;
+       addr[2] = &idx;
+       vlen[2] = 1;
+
+       while (len > 0) {
+               idx++;
+               if (idx == 1)
+                       ret = hmac_sha1_vector(key, key_len, 2, &addr[1],
+                                              &vlen[1], hash);
+               else
+                       ret = hmac_sha1_vector(key, key_len, 3, addr, vlen,
+                                              hash);
+               if (ret < 0)
+                       return -1;
+               if (len > SHA1_MAC_LEN) {
+                       os_memcpy(res, hash, SHA1_MAC_LEN);
+                       res += SHA1_MAC_LEN;
+                       len -= SHA1_MAC_LEN;
+               } else {
+                       os_memcpy(res, hash, len);
+                       len = 0;
+               }
+       }
+
+       return 0;
+}
+
+
+static int eap_eke_prf_hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+                                  size_t data_len, u8 *res, size_t len)
+{
+       u8 hash[SHA256_MAC_LEN];
+       u8 idx;
+       const u8 *addr[3];
+       size_t vlen[3];
+       int ret;
+
+       idx = 0;
+       addr[0] = hash;
+       vlen[0] = SHA256_MAC_LEN;
+       addr[1] = data;
+       vlen[1] = data_len;
+       addr[2] = &idx;
+       vlen[2] = 1;
+
+       while (len > 0) {
+               idx++;
+               if (idx == 1)
+                       ret = hmac_sha256_vector(key, key_len, 2, &addr[1],
+                                                &vlen[1], hash);
+               else
+                       ret = hmac_sha256_vector(key, key_len, 3, addr, vlen,
+                                                hash);
+               if (ret < 0)
+                       return -1;
+               if (len > SHA256_MAC_LEN) {
+                       os_memcpy(res, hash, SHA256_MAC_LEN);
+                       res += SHA256_MAC_LEN;
+                       len -= SHA256_MAC_LEN;
+               } else {
+                       os_memcpy(res, hash, len);
+                       len = 0;
+               }
+       }
+
+       return 0;
+}
+
+
+static int eap_eke_prfplus(u8 prf, const u8 *key, size_t key_len,
+                          const u8 *data, size_t data_len, u8 *res, size_t len)
+{
+       if (prf == EAP_EKE_PRF_HMAC_SHA1)
+               return eap_eke_prf_hmac_sha1(key, key_len, data, data_len, res,
+                                            len);
+       if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
+               return eap_eke_prf_hmac_sha256(key, key_len, data, data_len,
+                                              res, len);
+       return -1;
+}
+
+
+int eap_eke_derive_key(struct eap_eke_session *sess,
+                      const u8 *password, size_t password_len,
+                      const u8 *id_s, size_t id_s_len, const u8 *id_p,
+                      size_t id_p_len, u8 *key)
+{
+       u8 zeros[EAP_EKE_MAX_HASH_LEN];
+       u8 temp[EAP_EKE_MAX_HASH_LEN];
+       size_t key_len = 16; /* Only AES-128-CBC is used here */
+       u8 *id;
+
+       /* temp = prf(0+, password) */
+       os_memset(zeros, 0, sess->prf_len);
+       if (eap_eke_prf(sess->prf, zeros, sess->prf_len,
+                       password, password_len, NULL, 0, temp) < 0)
+               return -1;
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: temp = prf(0+, password)",
+                       temp, sess->prf_len);
+
+       /* key = prf+(temp, ID_S | ID_P) */
+       id = os_malloc(id_s_len + id_p_len);
+       if (id == NULL)
+               return -1;
+       os_memcpy(id, id_s, id_s_len);
+       os_memcpy(id + id_s_len, id_p, id_p_len);
+       wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: ID_S | ID_P",
+                         id, id_s_len + id_p_len);
+       if (eap_eke_prfplus(sess->prf, temp, sess->prf_len,
+                           id, id_s_len + id_p_len, key, key_len) < 0) {
+               os_free(id);
+               return -1;
+       }
+       os_free(id);
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: key = prf+(temp, ID_S | ID_P)",
+                       key, key_len);
+
+       return 0;
+}
+
+
+int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub,
+                  u8 *ret_dhcomp)
+{
+       u8 pub[EAP_EKE_MAX_DH_LEN];
+       int dh_len;
+       u8 iv[AES_BLOCK_SIZE];
+
+       dh_len = eap_eke_dh_len(sess->dhgroup);
+       if (dh_len < 0)
+               return -1;
+
+       /*
+        * DHComponent = Encr(key, y)
+        *
+        * All defined DH groups use primes that have length devisible by 16, so
+        * no need to do extra padding for y (= pub).
+        */
+       if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
+               return -1;
+       if (random_get_bytes(iv, AES_BLOCK_SIZE))
+               return -1;
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Encr(key, y)",
+                   iv, AES_BLOCK_SIZE);
+       os_memcpy(pub, dhpub, dh_len);
+       if (aes_128_cbc_encrypt(key, iv, pub, dh_len) < 0)
+               return -1;
+       os_memcpy(ret_dhcomp, iv, AES_BLOCK_SIZE);
+       os_memcpy(ret_dhcomp + AES_BLOCK_SIZE, pub, dh_len);
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent = Encr(key, y)",
+                   ret_dhcomp, AES_BLOCK_SIZE + dh_len);
+
+       return 0;
+}
+
+
+int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
+                         const u8 *dhpriv, const u8 *peer_dhcomp)
+{
+       u8 zeros[EAP_EKE_MAX_HASH_LEN];
+       u8 peer_pub[EAP_EKE_MAX_DH_LEN];
+       u8 modexp[EAP_EKE_MAX_DH_LEN];
+       size_t len;
+       const struct dh_group *dh;
+
+       if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
+               return -1;
+
+       dh = eap_eke_dh_group(sess->dhgroup);
+       if (dh == NULL)
+               return -1;
+
+       /* Decrypt peer DHComponent */
+       os_memcpy(peer_pub, peer_dhcomp + AES_BLOCK_SIZE, dh->prime_len);
+       if (aes_128_cbc_decrypt(key, peer_dhcomp, peer_pub, dh->prime_len) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt DHComponent");
+               return -1;
+       }
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted peer DH pubkey",
+                       peer_pub, dh->prime_len);
+
+       /* SharedSecret = prf(0+, g ^ (x_s * x_p) (mod p)) */
+       len = dh->prime_len;
+       if (crypto_mod_exp(peer_pub, dh->prime_len, dhpriv, dh->prime_len,
+                          dh->prime, dh->prime_len, modexp, &len) < 0)
+               return -1;
+       if (len < dh->prime_len) {
+               size_t pad = dh->prime_len - len;
+               os_memmove(modexp + pad, modexp, len);
+               os_memset(modexp, 0, pad);
+       }
+
+       os_memset(zeros, 0, sess->auth_len);
+       if (eap_eke_prf(sess->prf, zeros, sess->auth_len, modexp, dh->prime_len,
+                       NULL, 0, sess->shared_secret) < 0)
+               return -1;
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: SharedSecret",
+                       sess->shared_secret, sess->auth_len);
+
+       return 0;
+}
+
+
+int eap_eke_derive_ke_ki(struct eap_eke_session *sess,
+                        const u8 *id_s, size_t id_s_len,
+                        const u8 *id_p, size_t id_p_len)
+{
+       u8 buf[EAP_EKE_MAX_KE_LEN + EAP_EKE_MAX_KI_LEN];
+       size_t ke_len, ki_len;
+       u8 *data;
+       size_t data_len;
+       const char *label = "EAP-EKE Keys";
+       size_t label_len;
+
+       /*
+        * Ke | Ki = prf+(SharedSecret, "EAP-EKE Keys" | ID_S | ID_P)
+        * Ke = encryption key
+        * Ki = integrity protection key
+        * Length of each key depends on the selected algorithms.
+        */
+
+       if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+               ke_len = 16;
+       else
+               return -1;
+
+       if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+               ki_len = 20;
+       else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+               ki_len = 32;
+       else
+               return -1;
+
+       label_len = os_strlen(label);
+       data_len = label_len + id_s_len + id_p_len;
+       data = os_malloc(data_len);
+       if (data == NULL)
+               return -1;
+       os_memcpy(data, label, label_len);
+       os_memcpy(data + label_len, id_s, id_s_len);
+       os_memcpy(data + label_len + id_s_len, id_p, id_p_len);
+       if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+                           data, data_len, buf, ke_len + ki_len) < 0) {
+               os_free(data);
+               return -1;
+       }
+
+       os_memcpy(sess->ke, buf, ke_len);
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ke", sess->ke, ke_len);
+       os_memcpy(sess->ki, buf + ke_len, ki_len);
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ki", sess->ki, ki_len);
+
+       os_free(data);
+       return 0;
+}
+
+
+int eap_eke_derive_ka(struct eap_eke_session *sess,
+                     const u8 *id_s, size_t id_s_len,
+                     const u8 *id_p, size_t id_p_len,
+                     const u8 *nonce_p, const u8 *nonce_s)
+{
+       u8 *data, *pos;
+       size_t data_len;
+       const char *label = "EAP-EKE Ka";
+       size_t label_len;
+
+       /*
+        * Ka = prf+(SharedSecret, "EAP-EKE Ka" | ID_S | ID_P | Nonce_P |
+        *           Nonce_S)
+        * Ka = authentication key
+        * Length of the key depends on the selected algorithms.
+        */
+
+       label_len = os_strlen(label);
+       data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
+       data = os_malloc(data_len);
+       if (data == NULL)
+               return -1;
+       pos = data;
+       os_memcpy(pos, label, label_len);
+       pos += label_len;
+       os_memcpy(pos, id_s, id_s_len);
+       pos += id_s_len;
+       os_memcpy(pos, id_p, id_p_len);
+       pos += id_p_len;
+       os_memcpy(pos, nonce_p, sess->nonce_len);
+       pos += sess->nonce_len;
+       os_memcpy(pos, nonce_s, sess->nonce_len);
+       if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+                           data, data_len, sess->ka, sess->prf_len) < 0) {
+               os_free(data);
+               return -1;
+       }
+       os_free(data);
+
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka", sess->ka, sess->prf_len);
+
+       return 0;
+}
+
+
+int eap_eke_derive_msk(struct eap_eke_session *sess,
+                      const u8 *id_s, size_t id_s_len,
+                      const u8 *id_p, size_t id_p_len,
+                      const u8 *nonce_p, const u8 *nonce_s,
+                      u8 *msk, u8 *emsk)
+{
+       u8 *data, *pos;
+       size_t data_len;
+       const char *label = "EAP-EKE Exported Keys";
+       size_t label_len;
+       u8 buf[EAP_MSK_LEN + EAP_EMSK_LEN];
+
+       /*
+        * MSK | EMSK = prf+(SharedSecret, "EAP-EKE Exported Keys" | ID_S |
+        *                   ID_P | Nonce_P | Nonce_S)
+        */
+
+       label_len = os_strlen(label);
+       data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
+       data = os_malloc(data_len);
+       if (data == NULL)
+               return -1;
+       pos = data;
+       os_memcpy(pos, label, label_len);
+       pos += label_len;
+       os_memcpy(pos, id_s, id_s_len);
+       pos += id_s_len;
+       os_memcpy(pos, id_p, id_p_len);
+       pos += id_p_len;
+       os_memcpy(pos, nonce_p, sess->nonce_len);
+       pos += sess->nonce_len;
+       os_memcpy(pos, nonce_s, sess->nonce_len);
+       if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
+                           data, data_len, buf, EAP_MSK_LEN + EAP_EMSK_LEN) <
+           0) {
+               os_free(data);
+               return -1;
+       }
+       os_free(data);
+
+       os_memcpy(msk, buf, EAP_MSK_LEN);
+       os_memcpy(emsk, buf + EAP_MSK_LEN, EAP_EMSK_LEN);
+       os_memset(buf, 0, sizeof(buf));
+
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: MSK", msk, EAP_MSK_LEN);
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: EMSK", msk, EAP_EMSK_LEN);
+
+       return 0;
+}
+
+
+static int eap_eke_mac(u8 mac, const u8 *key, const u8 *data, size_t data_len,
+                      u8 *res)
+{
+       if (mac == EAP_EKE_MAC_HMAC_SHA1)
+               return hmac_sha1(key, SHA1_MAC_LEN, data, data_len, res);
+       if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
+               return hmac_sha256(key, SHA256_MAC_LEN, data, data_len, res);
+       return -1;
+}
+
+
+int eap_eke_prot(struct eap_eke_session *sess,
+                const u8 *data, size_t data_len,
+                u8 *prot, size_t *prot_len)
+{
+       size_t block_size, icv_len, pad;
+       u8 *pos, *iv, *e;
+
+       if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+               block_size = AES_BLOCK_SIZE;
+       else
+               return -1;
+
+       if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+               icv_len = SHA1_MAC_LEN;
+       else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+               icv_len = SHA256_MAC_LEN;
+       else
+               return -1;
+
+       pad = data_len % block_size;
+       if (pad)
+               pad = block_size - pad;
+
+       if (*prot_len < block_size + data_len + pad + icv_len) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for Prot() data");
+       }
+       pos = prot;
+
+       if (random_get_bytes(pos, block_size))
+               return -1;
+       iv = pos;
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Prot()", iv, block_size);
+       pos += block_size;
+
+       e = pos;
+       os_memcpy(pos, data, data_len);
+       pos += data_len;
+       if (pad) {
+               if (random_get_bytes(pos, pad))
+                       return -1;
+               pos += pad;
+       }
+
+       if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
+               return -1;
+
+       if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
+               return -1;
+       pos += icv_len;
+
+       *prot_len = pos - prot;
+       return 0;
+}
+
+
+int eap_eke_decrypt_prot(struct eap_eke_session *sess,
+                        const u8 *prot, size_t prot_len,
+                        u8 *data, size_t *data_len)
+{
+       size_t block_size, icv_len;
+       u8 icv[EAP_EKE_MAX_HASH_LEN];
+
+       if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
+               block_size = AES_BLOCK_SIZE;
+       else
+               return -1;
+
+       if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
+               icv_len = SHA1_MAC_LEN;
+       else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
+               icv_len = SHA256_MAC_LEN;
+       else
+               return -1;
+
+       if (prot_len < 2 * block_size + icv_len)
+               return -1;
+       if ((prot_len - icv_len) % block_size)
+               return -1;
+
+       if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
+                       prot_len - block_size - icv_len, icv) < 0)
+               return -1;
+       if (os_memcmp(icv, prot + prot_len - icv_len, icv_len) != 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: ICV mismatch in Prot() data");
+               return -1;
+       }
+
+       if (*data_len < prot_len - block_size - icv_len) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for decrypted Prot() data");
+               return -1;
+       }
+
+       *data_len = prot_len - block_size - icv_len;
+       os_memcpy(data, prot + block_size, *data_len);
+       if (aes_128_cbc_decrypt(sess->ke, prot, data, *data_len) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt Prot() data");
+               return -1;
+       }
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted Prot() data",
+                       data, *data_len);
+
+       return 0;
+}
+
+
+int eap_eke_auth(struct eap_eke_session *sess, const char *label,
+                const struct wpabuf *msgs, u8 *auth)
+{
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Auth(%s)", label);
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka for Auth",
+                       sess->ka, sess->auth_len);
+       wpa_hexdump_buf(MSG_MSGDUMP, "EAP-EKE: Messages for Auth", msgs);
+       return eap_eke_prf(sess->prf, sess->ka, sess->auth_len,
+                          (const u8 *) label, os_strlen(label),
+                          wpabuf_head(msgs), wpabuf_len(msgs), auth);
+}
+
+
+int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
+                        u8 prf, u8 mac)
+{
+       sess->dhgroup = dhgroup;
+       sess->encr = encr;
+       sess->prf = prf;
+       sess->mac = mac;
+
+       sess->prf_len = eap_eke_prf_len(prf);
+       if (sess->prf_len < 0)
+               return -1;
+       sess->nonce_len = eap_eke_nonce_len(prf);
+       if (sess->nonce_len < 0)
+               return -1;
+       sess->auth_len = eap_eke_auth_len(prf);
+       if (sess->auth_len < 0)
+               return -1;
+       sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
+       if (sess->dhcomp_len < 0)
+               return -1;
+       sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
+       if (sess->pnonce_len < 0)
+               return -1;
+       sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
+       if (sess->pnonce_ps_len < 0)
+               return -1;
+
+       return 0;
+}
+
+
+void eap_eke_session_clean(struct eap_eke_session *sess)
+{
+       os_memset(sess->shared_secret, 0, EAP_EKE_MAX_HASH_LEN);
+       os_memset(sess->ke, 0, EAP_EKE_MAX_KE_LEN);
+       os_memset(sess->ki, 0, EAP_EKE_MAX_KI_LEN);
+       os_memset(sess->ka, 0, EAP_EKE_MAX_KA_LEN);
+}
diff --git a/src/eap_common/eap_eke_common.h b/src/eap_common/eap_eke_common.h
new file mode 100644 (file)
index 0000000..a4c0422
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * EAP server/peer: EAP-EKE shared routines
+ * Copyright (c) 2011-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_EKE_COMMON_H
+#define EAP_EKE_COMMON_H
+
+/* EKE Exchange */
+#define EAP_EKE_ID 1
+#define EAP_EKE_COMMIT 2
+#define EAP_EKE_CONFIRM 3
+#define EAP_EKE_FAILURE 4
+
+/* Diffie-Hellman Group Registry */
+#define EAP_EKE_DHGROUP_EKE_2 1
+#define EAP_EKE_DHGROUP_EKE_5 2
+#define EAP_EKE_DHGROUP_EKE_14 3 /* mandatory to implement */
+#define EAP_EKE_DHGROUP_EKE_15 4
+#define EAP_EKE_DHGROUP_EKE_16 5
+
+/* Encryption Algorithm Registry */
+#define EAP_EKE_ENCR_AES128_CBC 1 /* mandatory to implement */
+
+/* Pseudo Random Function Registry */
+#define EAP_EKE_PRF_HMAC_SHA1 1 /* mandatory to implement */
+#define EAP_EKE_PRF_HMAC_SHA2_256 2
+
+/* Keyed Message Digest (MAC) Registry */
+#define EAP_EKE_MAC_HMAC_SHA1 1 /* mandatory to implement */
+#define EAP_EKE_MAC_HMAC_SHA2_256 2
+
+/* Identity Type Registry */
+#define EAP_EKE_ID_OPAQUE 1
+#define EAP_EKE_ID_NAI 2
+#define EAP_EKE_ID_IPv4 3
+#define EAP_EKE_ID_IPv6 4
+#define EAP_EKE_ID_FQDN 5
+#define EAP_EKE_ID_DN 6
+
+/* Failure-Code */
+#define EAP_EKE_FAIL_NO_ERROR 1
+#define EAP_EKE_FAIL_PROTO_ERROR 2
+#define EAP_EKE_FAIL_PASSWD_NOT_FOUND 3
+#define EAP_EKE_FAIL_AUTHENTICATION_FAIL 4
+#define EAP_EKE_FAIL_AUTHORIZATION_FAIL 5
+#define EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN 6
+#define EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR 0xffffffff
+
+#define EAP_EKE_MAX_DH_LEN 512
+#define EAP_EKE_MAX_HASH_LEN 32
+#define EAP_EKE_MAX_KEY_LEN 16
+#define EAP_EKE_MAX_KE_LEN 16
+#define EAP_EKE_MAX_KI_LEN 32
+#define EAP_EKE_MAX_KA_LEN 32
+#define EAP_EKE_MAX_NONCE_LEN 16
+
+struct eap_eke_session {
+       /* Selected proposal */
+       u8 dhgroup;
+       u8 encr;
+       u8 prf;
+       u8 mac;
+
+       u8 shared_secret[EAP_EKE_MAX_HASH_LEN];
+       u8 ke[EAP_EKE_MAX_KE_LEN];
+       u8 ki[EAP_EKE_MAX_KI_LEN];
+       u8 ka[EAP_EKE_MAX_KA_LEN];
+
+       int prf_len;
+       int nonce_len;
+       int auth_len;
+       int dhcomp_len;
+       int pnonce_len;
+       int pnonce_ps_len;
+};
+
+int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
+                        u8 prf, u8 mac);
+void eap_eke_session_clean(struct eap_eke_session *sess);
+int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub);
+int eap_eke_derive_key(struct eap_eke_session *sess,
+                      const u8 *password, size_t password_len,
+                      const u8 *id_s, size_t id_s_len, const u8 *id_p,
+                      size_t id_p_len, u8 *key);
+int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub,
+                  u8 *ret_dhcomp);
+int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
+                         const u8 *dhpriv, const u8 *peer_dhcomp);
+int eap_eke_derive_ke_ki(struct eap_eke_session *sess,
+                        const u8 *id_s, size_t id_s_len,
+                        const u8 *id_p, size_t id_p_len);
+int eap_eke_derive_ka(struct eap_eke_session *sess,
+                     const u8 *id_s, size_t id_s_len,
+                     const u8 *id_p, size_t id_p_len,
+                     const u8 *nonce_p, const u8 *nonce_s);
+int eap_eke_derive_msk(struct eap_eke_session *sess,
+                      const u8 *id_s, size_t id_s_len,
+                      const u8 *id_p, size_t id_p_len,
+                      const u8 *nonce_p, const u8 *nonce_s,
+                      u8 *msk, u8 *emsk);
+int eap_eke_prot(struct eap_eke_session *sess,
+                const u8 *data, size_t data_len,
+                u8 *prot, size_t *prot_len);
+int eap_eke_decrypt_prot(struct eap_eke_session *sess,
+                        const u8 *prot, size_t prot_len,
+                        u8 *data, size_t *data_len);
+int eap_eke_auth(struct eap_eke_session *sess, const char *label,
+                const struct wpabuf *msgs, u8 *auth);
+
+#endif /* EAP_EKE_COMMON_H */
index ed90919..42f525b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer configuration data
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -634,6 +634,15 @@ struct eap_peer_config {
         *         password field is the name of that external entry
         */
        u32 flags;
+
+       /**
+        * ocsp - Whether to use/require OCSP to check server certificate
+        *
+        * 0 = do not use OCSP stapling (TLS certificate status extension)
+        * 1 = try to use OCSP stapling, but not require response
+        * 2 = require valid OCSP stapling response
+        */
+       int ocsp;
 };
 
 
diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c
new file mode 100644 (file)
index 0000000..c71db5f
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * EAP peer method: EAP-EKE (RFC 6124)
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/random.h"
+#include "eap_peer/eap_i.h"
+#include "eap_common/eap_eke_common.h"
+
+struct eap_eke_data {
+       enum {
+               IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE
+       } state;
+       u8 msk[EAP_MSK_LEN];
+       u8 emsk[EAP_EMSK_LEN];
+       u8 *peerid;
+       size_t peerid_len;
+       u8 *serverid;
+       size_t serverid_len;
+       u8 dh_priv[EAP_EKE_MAX_DH_LEN];
+       struct eap_eke_session sess;
+       u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
+       u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
+       struct wpabuf *msgs;
+};
+
+
+static const char * eap_eke_state_txt(int state)
+{
+       switch (state) {
+       case IDENTITY:
+               return "IDENTITY";
+       case COMMIT:
+               return "COMMIT";
+       case CONFIRM:
+               return "CONFIRM";
+       case SUCCESS:
+               return "SUCCESS";
+       case FAILURE:
+               return "FAILURE";
+       default:
+               return "?";
+       }
+}
+
+
+static void eap_eke_state(struct eap_eke_data *data, int state)
+{
+       wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
+                  eap_eke_state_txt(data->state), eap_eke_state_txt(state));
+       data->state = state;
+}
+
+
+static void eap_eke_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_eke_init(struct eap_sm *sm)
+{
+       struct eap_eke_data *data;
+       const u8 *identity, *password;
+       size_t identity_len, password_len;
+
+       password = eap_get_config_password(sm, &password_len);
+       if (!password) {
+               wpa_printf(MSG_INFO, "EAP-EKE: No password configured");
+               return NULL;
+       }
+
+       data = os_zalloc(sizeof(*data));
+       if (data == NULL)
+               return NULL;
+       eap_eke_state(data, IDENTITY);
+
+       identity = eap_get_config_identity(sm, &identity_len);
+       if (identity) {
+               data->peerid = os_malloc(identity_len);
+               if (data->peerid == NULL) {
+                       eap_eke_deinit(sm, data);
+                       return NULL;
+               }
+               os_memcpy(data->peerid, identity, identity_len);
+               data->peerid_len = identity_len;
+       }
+
+       return data;
+}
+
+
+static void eap_eke_deinit(struct eap_sm *sm, void *priv)
+{
+       struct eap_eke_data *data = priv;
+       eap_eke_session_clean(&data->sess);
+       os_free(data->serverid);
+       os_free(data->peerid);
+       wpabuf_free(data->msgs);
+       os_free(data);
+}
+
+
+static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id,
+                                        size_t length, u8 eke_exch)
+{
+       struct wpabuf *msg;
+       size_t plen;
+
+       plen = 1 + length;
+
+       msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
+                           EAP_CODE_RESPONSE, id);
+       if (msg == NULL) {
+               wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
+               return NULL;
+       }
+
+       wpabuf_put_u8(msg, eke_exch);
+
+       return msg;
+}
+
+
+static int eap_eke_supp_dhgroup(u8 dhgroup)
+{
+       return dhgroup == EAP_EKE_DHGROUP_EKE_2 ||
+               dhgroup == EAP_EKE_DHGROUP_EKE_5 ||
+               dhgroup == EAP_EKE_DHGROUP_EKE_14 ||
+               dhgroup == EAP_EKE_DHGROUP_EKE_15 ||
+               dhgroup == EAP_EKE_DHGROUP_EKE_16;
+}
+
+
+static int eap_eke_supp_encr(u8 encr)
+{
+       return encr == EAP_EKE_ENCR_AES128_CBC;
+}
+
+
+static int eap_eke_supp_prf(u8 prf)
+{
+       return prf == EAP_EKE_PRF_HMAC_SHA1 ||
+               prf == EAP_EKE_PRF_HMAC_SHA2_256;
+}
+
+
+static int eap_eke_supp_mac(u8 mac)
+{
+       return mac == EAP_EKE_MAC_HMAC_SHA1 ||
+               mac == EAP_EKE_MAC_HMAC_SHA2_256;
+}
+
+
+static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data,
+                                         struct eap_method_ret *ret,
+                                         const struct wpabuf *reqData,
+                                         u32 failure_code)
+{
+       struct wpabuf *resp;
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x",
+                  failure_code);
+
+       resp = eap_eke_build_msg(data, eap_get_id(reqData), 4, EAP_EKE_FAILURE);
+       if (resp)
+               wpabuf_put_be32(resp, failure_code);
+
+       os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+       eap_eke_session_clean(&data->sess);
+
+       eap_eke_state(data, FAILURE);
+       ret->methodState = METHOD_DONE;
+       ret->decision = DECISION_FAIL;
+       ret->allowNotifications = FALSE;
+
+       return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data,
+                                         struct eap_method_ret *ret,
+                                         const struct wpabuf *reqData,
+                                         const u8 *payload,
+                                         size_t payload_len)
+{
+       struct wpabuf *resp;
+       unsigned num_prop, i;
+       const u8 *pos, *end;
+       const u8 *prop = NULL;
+       u8 idtype;
+
+       if (data->state != IDENTITY) {
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PROTO_ERROR);
+       }
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request");
+
+       if (payload_len < 2 + 4) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data");
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PROTO_ERROR);
+       }
+
+       pos = payload;
+       end = payload + payload_len;
+
+       num_prop = *pos++;
+       pos++; /* Ignore Reserved field */
+
+       if (pos + num_prop * 4 > end) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)",
+                          num_prop);
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PROTO_ERROR);
+       }
+
+       for (i = 0; i < num_prop; i++) {
+               const u8 *tmp = pos;
+
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u",
+                          i, pos[0], pos[1], pos[2], pos[3]);
+               pos += 4;
+
+               if (!eap_eke_supp_dhgroup(*tmp))
+                       continue;
+               tmp++;
+               if (!eap_eke_supp_encr(*tmp))
+                       continue;
+               tmp++;
+               if (!eap_eke_supp_prf(*tmp))
+                       continue;
+               tmp++;
+               if (!eap_eke_supp_mac(*tmp))
+                       continue;
+
+               prop = tmp - 3;
+               if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2],
+                                        prop[3]) < 0) {
+                       prop = NULL;
+                       continue;
+               }
+
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal");
+               break;
+       }
+
+       if (prop == NULL) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found");
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN);
+       }
+
+       pos += (num_prop - i - 1) * 4;
+
+       if (pos == end) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity");
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PROTO_ERROR);
+       }
+
+       idtype = *pos++;
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype);
+       wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity",
+                         pos, end - pos);
+       os_free(data->serverid);
+       data->serverid = os_malloc(end - pos);
+       if (data->serverid == NULL) {
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+       os_memcpy(data->serverid, pos, end - pos);
+       data->serverid_len = end - pos;
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response");
+
+       resp = eap_eke_build_msg(data, eap_get_id(reqData),
+                                2 + 4 + 1 + data->peerid_len,
+                                EAP_EKE_ID);
+       if (resp == NULL) {
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+
+       wpabuf_put_u8(resp, 1); /* NumProposals */
+       wpabuf_put_u8(resp, 0); /* Reserved */
+       wpabuf_put_data(resp, prop, 4); /* Selected Proposal */
+       wpabuf_put_u8(resp, EAP_EKE_ID_NAI);
+       if (data->peerid)
+               wpabuf_put_data(resp, data->peerid, data->peerid_len);
+
+       wpabuf_free(data->msgs);
+       data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp));
+       if (data->msgs == NULL) {
+               wpabuf_free(resp);
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+       wpabuf_put_buf(data->msgs, reqData);
+       wpabuf_put_buf(data->msgs, resp);
+
+       eap_eke_state(data, COMMIT);
+
+       return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
+                                             struct eap_eke_data *data,
+                                             struct eap_method_ret *ret,
+                                             const struct wpabuf *reqData,
+                                             const u8 *payload,
+                                             size_t payload_len)
+{
+       struct wpabuf *resp;
+       const u8 *pos, *end, *dhcomp;
+       size_t prot_len;
+       u8 *rpos;
+       u8 key[EAP_EKE_MAX_KEY_LEN];
+       u8 pub[EAP_EKE_MAX_DH_LEN];
+       const u8 *password;
+       size_t password_len;
+
+       if (data->state != COMMIT) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state);
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PROTO_ERROR);
+       }
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request");
+
+       password = eap_get_config_password(sm, &password_len);
+       if (password == NULL) {
+               wpa_printf(MSG_INFO, "EAP-EKE: No password configured!");
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+       }
+
+       pos = payload;
+       end = payload + payload_len;
+
+       if (pos + data->sess.dhcomp_len > end) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PROTO_ERROR);
+       }
+
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S",
+                   pos, data->sess.dhcomp_len);
+       dhcomp = pos;
+       pos += data->sess.dhcomp_len;
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
+
+       /*
+        * temp = prf(0+, password)
+        * key = prf+(temp, ID_S | ID_P)
+        */
+       if (eap_eke_derive_key(&data->sess, password, password_len,
+                              data->serverid, data->serverid_len,
+                              data->peerid, data->peerid_len, key) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+
+       /*
+        * y_p = g ^ x_p (mod p)
+        * x_p = random number 2 .. p-1
+        */
+       if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
+               os_memset(key, 0, sizeof(key));
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+
+       if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
+       {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
+               os_memset(key, 0, sizeof(key));
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+
+       if (eap_eke_derive_ke_ki(&data->sess,
+                                data->serverid, data->serverid_len,
+                                data->peerid, data->peerid_len) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
+               os_memset(key, 0, sizeof(key));
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response");
+
+       resp = eap_eke_build_msg(data, eap_get_id(reqData),
+                                data->sess.dhcomp_len + data->sess.pnonce_len,
+                                EAP_EKE_COMMIT);
+       if (resp == NULL) {
+               os_memset(key, 0, sizeof(key));
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+
+       /* DHComponent_P = Encr(key, y_p) */
+       rpos = wpabuf_put(resp, data->sess.dhcomp_len);
+       if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
+               os_memset(key, 0, sizeof(key));
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+       os_memset(key, 0, sizeof(key));
+
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
+                   rpos, data->sess.dhcomp_len);
+
+       if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) {
+               wpabuf_free(resp);
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
+                       data->nonce_p, data->sess.nonce_len);
+       prot_len = wpabuf_tailroom(resp);
+       if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len,
+                        wpabuf_put(resp, 0), &prot_len) < 0) {
+               wpabuf_free(resp);
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P",
+                   wpabuf_put(resp, 0), prot_len);
+       wpabuf_put(resp, prot_len);
+
+       /* TODO: CBValue */
+
+       if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp))
+           < 0) {
+               wpabuf_free(resp);
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+       wpabuf_put_buf(data->msgs, reqData);
+       wpabuf_put_buf(data->msgs, resp);
+
+       eap_eke_state(data, CONFIRM);
+
+       return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
+                                              struct eap_method_ret *ret,
+                                              const struct wpabuf *reqData,
+                                              const u8 *payload,
+                                              size_t payload_len)
+{
+       struct wpabuf *resp;
+       const u8 *pos, *end;
+       size_t prot_len;
+       u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
+       u8 auth_s[EAP_EKE_MAX_HASH_LEN];
+       size_t decrypt_len;
+       u8 *auth;
+
+       if (data->state != CONFIRM) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)",
+                          data->state);
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PROTO_ERROR);
+       }
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request");
+
+       pos = payload;
+       end = payload + payload_len;
+
+       if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PROTO_ERROR);
+       }
+
+       decrypt_len = sizeof(nonces);
+       if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len,
+                                nonces, &decrypt_len) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS");
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+       }
+       if (decrypt_len != (size_t) 2 * data->sess.nonce_len) {
+               wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S");
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+       }
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
+                       nonces, 2 * data->sess.nonce_len);
+       if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match trnsmitted Nonce_P");
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+       }
+
+       os_memcpy(data->nonce_s, nonces + data->sess.nonce_len,
+                 data->sess.nonce_len);
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
+                       data->nonce_s, data->sess.nonce_len);
+
+       if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len,
+                             data->peerid, data->peerid_len,
+                             data->nonce_p, data->nonce_s) < 0) {
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+
+       if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0)
+       {
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len);
+       if (os_memcmp(auth_s, pos + data->sess.pnonce_ps_len,
+                     data->sess.prf_len) != 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match");
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+       }
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response");
+
+       resp = eap_eke_build_msg(data, eap_get_id(reqData),
+                                data->sess.pnonce_len + data->sess.prf_len,
+                                EAP_EKE_CONFIRM);
+       if (resp == NULL) {
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+
+       prot_len = wpabuf_tailroom(resp);
+       if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len,
+                        wpabuf_put(resp, 0), &prot_len) < 0) {
+               wpabuf_free(resp);
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+       wpabuf_put(resp, prot_len);
+
+       auth = wpabuf_put(resp, data->sess.prf_len);
+       if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) {
+               wpabuf_free(resp);
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len);
+
+       if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len,
+                              data->peerid, data->peerid_len,
+                              data->nonce_s, data->nonce_p,
+                              data->msk, data->emsk) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
+               wpabuf_free(resp);
+               return eap_eke_build_fail(data, ret, reqData,
+                                         EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+       }
+
+       os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+       eap_eke_session_clean(&data->sess);
+
+       eap_eke_state(data, SUCCESS);
+       ret->methodState = METHOD_MAY_CONT;
+       ret->decision = DECISION_COND_SUCC;
+       ret->allowNotifications = FALSE;
+
+       return resp;
+}
+
+
+static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data,
+                                              struct eap_method_ret *ret,
+                                              const struct wpabuf *reqData,
+                                              const u8 *payload,
+                                              size_t payload_len)
+{
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request");
+
+       if (payload_len < 4) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
+       } else {
+               u32 code;
+               code = WPA_GET_BE32(payload);
+               wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code);
+       }
+
+       return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_NO_ERROR);
+}
+
+
+static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
+                                      struct eap_method_ret *ret,
+                                      const struct wpabuf *reqData)
+{
+       struct eap_eke_data *data = priv;
+       struct wpabuf *resp;
+       const u8 *pos, *end;
+       size_t len;
+       u8 eke_exch;
+
+       pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
+       if (pos == NULL || len < 1) {
+               ret->ignore = TRUE;
+               return NULL;
+       }
+
+       end = pos + len;
+       eke_exch = *pos++;
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
+
+       ret->ignore = FALSE;
+       ret->methodState = METHOD_MAY_CONT;
+       ret->decision = DECISION_FAIL;
+       ret->allowNotifications = TRUE;
+
+       switch (eke_exch) {
+       case EAP_EKE_ID:
+               resp = eap_eke_process_id(data, ret, reqData, pos, end - pos);
+               break;
+       case EAP_EKE_COMMIT:
+               resp = eap_eke_process_commit(sm, data, ret, reqData,
+                                             pos, end - pos);
+               break;
+       case EAP_EKE_CONFIRM:
+               resp = eap_eke_process_confirm(data, ret, reqData,
+                                              pos, end - pos);
+               break;
+       case EAP_EKE_FAILURE:
+               resp = eap_eke_process_failure(data, ret, reqData,
+                                              pos, end - pos);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
+               ret->ignore = TRUE;
+               return NULL;
+       }
+
+       if (ret->methodState == METHOD_DONE)
+               ret->allowNotifications = FALSE;
+
+       return resp;
+}
+
+
+static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+       struct eap_eke_data *data = priv;
+       return data->state == SUCCESS;
+}
+
+
+static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_eke_data *data = priv;
+       u8 *key;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       key = os_malloc(EAP_MSK_LEN);
+       if (key == NULL)
+               return NULL;
+       os_memcpy(key, data->msk, EAP_MSK_LEN);
+       *len = EAP_MSK_LEN;
+
+       return key;
+}
+
+
+static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_eke_data *data = priv;
+       u8 *key;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       key = os_malloc(EAP_EMSK_LEN);
+       if (key == NULL)
+               return NULL;
+       os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+       *len = EAP_EMSK_LEN;
+
+       return key;
+}
+
+
+int eap_peer_eke_register(void)
+{
+       struct eap_method *eap;
+       int ret;
+
+       eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+                                   EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
+       if (eap == NULL)
+               return -1;
+
+       eap->init = eap_eke_init;
+       eap->deinit = eap_eke_deinit;
+       eap->process = eap_eke_process;
+       eap->isKeyAvailable = eap_eke_isKeyAvailable;
+       eap->getKey = eap_eke_getKey;
+       eap->get_emsk = eap_eke_get_emsk;
+
+       ret = eap_peer_method_register(eap);
+       if (ret)
+               eap_peer_method_free(eap);
+       return ret;
+}
index 4994ff1..a465fd2 100644 (file)
@@ -105,5 +105,6 @@ int eap_peer_ikev2_register(void);
 int eap_peer_vendor_test_register(void);
 int eap_peer_tnc_register(void);
 int eap_peer_pwd_register(void);
+int eap_peer_eke_register(void);
 
 #endif /* EAP_METHODS_H */
index a777bb0..be8c301 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -164,6 +164,10 @@ static int eap_tls_init_connection(struct eap_sm *sm,
 {
        int res;
 
+       if (config->ocsp)
+               params->flags |= TLS_CONN_REQUEST_OCSP;
+       if (config->ocsp == 2)
+               params->flags |= TLS_CONN_REQUIRE_OCSP;
        data->conn = tls_connection_init(data->ssl_ctx);
        if (data->conn == NULL) {
                wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
index f2a7cd7..36b230b 100644 (file)
@@ -104,6 +104,9 @@ struct eap_config {
        int fragment_size;
 
        int pbc_in_m1;
+
+       const u8 *server_id;
+       size_t server_id_len;
 };
 
 
index f92704a..003e202 100644 (file)
@@ -188,6 +188,9 @@ struct eap_sm {
        int fragment_size;
 
        int pbc_in_m1;
+
+       const u8 *server_id;
+       size_t server_id_len;
 };
 
 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
index bc810a9..429cb72 100644 (file)
@@ -45,5 +45,6 @@ int eap_server_wsc_register(void);
 int eap_server_ikev2_register(void);
 int eap_server_tnc_register(void);
 int eap_server_pwd_register(void);
+int eap_server_eke_register(void);
 
 #endif /* EAP_SERVER_METHODS_H */
index 15f7e22..54b7533 100644 (file)
@@ -1278,6 +1278,8 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx,
        sm->fragment_size = conf->fragment_size;
        sm->pwd_group = conf->pwd_group;
        sm->pbc_in_m1 = conf->pbc_in_m1;
+       sm->server_id = conf->server_id;
+       sm->server_id_len = conf->server_id_len;
 
        wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
 
diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c
new file mode 100644 (file)
index 0000000..b19a321
--- /dev/null
@@ -0,0 +1,793 @@
+/*
+ * hostapd / EAP-EKE (RFC 6124) server
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/random.h"
+#include "eap_server/eap_i.h"
+#include "eap_common/eap_eke_common.h"
+
+
+struct eap_eke_data {
+       enum {
+               IDENTITY, COMMIT, CONFIRM, FAILURE_REPORT, SUCCESS, FAILURE
+       } state;
+       u8 msk[EAP_MSK_LEN];
+       u8 emsk[EAP_EMSK_LEN];
+       u8 *peerid;
+       size_t peerid_len;
+       u8 peerid_type;
+       u8 serverid_type;
+       u8 dh_priv[EAP_EKE_MAX_DH_LEN];
+       u8 key[EAP_EKE_MAX_KEY_LEN];
+       struct eap_eke_session sess;
+       u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
+       u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
+       struct wpabuf *msgs;
+       int phase2;
+       u32 failure_code;
+};
+
+
+static const char * eap_eke_state_txt(int state)
+{
+       switch (state) {
+       case IDENTITY:
+               return "IDENTITY";
+       case COMMIT:
+               return "COMMIT";
+       case CONFIRM:
+               return "CONFIRM";
+       case FAILURE_REPORT:
+               return "FAILURE_REPORT";
+       case SUCCESS:
+               return "SUCCESS";
+       case FAILURE:
+               return "FAILURE";
+       default:
+               return "?";
+       }
+}
+
+
+static void eap_eke_state(struct eap_eke_data *data, int state)
+{
+       wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
+                  eap_eke_state_txt(data->state),
+                  eap_eke_state_txt(state));
+       data->state = state;
+}
+
+
+static void eap_eke_fail(struct eap_eke_data *data, u32 code)
+{
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Failure - code 0x%x", code);
+       data->failure_code = code;
+       eap_eke_state(data, FAILURE_REPORT);
+}
+
+
+static void * eap_eke_init(struct eap_sm *sm)
+{
+       struct eap_eke_data *data;
+       size_t i;
+
+       data = os_zalloc(sizeof(*data));
+       if (data == NULL)
+               return NULL;
+       eap_eke_state(data, IDENTITY);
+
+       data->serverid_type = EAP_EKE_ID_OPAQUE;
+       for (i = 0; i < sm->server_id_len; i++) {
+               if (sm->server_id[i] == '.' &&
+                   data->serverid_type == EAP_EKE_ID_OPAQUE)
+                       data->serverid_type = EAP_EKE_ID_FQDN;
+               if (sm->server_id[i] == '@')
+                       data->serverid_type = EAP_EKE_ID_NAI;
+       }
+
+       data->phase2 = sm->init_phase2;
+
+       return data;
+}
+
+
+static void eap_eke_reset(struct eap_sm *sm, void *priv)
+{
+       struct eap_eke_data *data = priv;
+       eap_eke_session_clean(&data->sess);
+       os_free(data->peerid);
+       wpabuf_free(data->msgs);
+       os_free(data);
+}
+
+
+static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data,
+                                        u8 id, size_t length, u8 eke_exch)
+{
+       struct wpabuf *msg;
+       size_t plen;
+
+       plen = 1 + length;
+
+       msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
+                           EAP_CODE_REQUEST, id);
+       if (msg == NULL) {
+               wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
+               return NULL;
+       }
+
+       wpabuf_put_u8(msg, eke_exch);
+
+       return msg;
+}
+
+
+static int supported_proposal(const u8 *pos)
+{
+       if (pos[0] == EAP_EKE_DHGROUP_EKE_16 &&
+           pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+           pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+           pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+               return 1;
+
+       if (pos[0] == EAP_EKE_DHGROUP_EKE_15 &&
+           pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+           pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+           pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+               return 1;
+
+       if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
+           pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+           pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 &&
+           pos[3] == EAP_EKE_MAC_HMAC_SHA2_256)
+               return 1;
+
+       if (pos[0] == EAP_EKE_DHGROUP_EKE_14 &&
+           pos[1] == EAP_EKE_ENCR_AES128_CBC &&
+           pos[2] == EAP_EKE_PRF_HMAC_SHA1 &&
+           pos[3] == EAP_EKE_MAC_HMAC_SHA1)
+               return 1;
+
+       return 0;
+}
+
+
+static struct wpabuf * eap_eke_build_failure(struct eap_eke_data *data, u8 id)
+{
+       struct wpabuf *msg;
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Failure: Failure-Code=0x%x",
+                  data->failure_code);
+
+       msg = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE);
+       if (msg == NULL) {
+               eap_eke_state(data, FAILURE);
+               return NULL;
+       }
+       wpabuf_put_be32(msg, data->failure_code);
+
+       return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_identity(struct eap_sm *sm,
+                                             struct eap_eke_data *data,
+                                             u8 id)
+{
+       struct wpabuf *msg;
+       size_t plen;
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity");
+
+       plen = 2 + 4 * 4 + 1 + sm->server_id_len;
+       msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID);
+       if (msg == NULL)
+               return NULL;
+
+       wpabuf_put_u8(msg, 4); /* NumProposals */
+       wpabuf_put_u8(msg, 0); /* Reserved */
+
+       /* Proposal - DH Group 16 with AES128-CBC and SHA256 */
+       wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_16); /* Group Description */
+       wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+       wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+       wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+       /* Proposal - DH Group 15 with AES128-CBC and SHA256 */
+       wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_15); /* Group Description */
+       wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+       wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+       wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+       /* Proposal - DH Group 14 with AES128-CBC and SHA256 */
+       wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
+       wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+       wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */
+       wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */
+
+       /*
+        * Proposal - DH Group 14 with AES128-CBC and SHA1
+        * (mandatory to implement algorithms)
+        */
+       wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */
+       wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */
+       wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA1); /* PRF */
+       wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA1); /* MAC */
+
+       /* Server IDType + Identity */
+       wpabuf_put_u8(msg, data->serverid_type);
+       wpabuf_put_data(msg, sm->server_id, sm->server_id_len);
+
+       wpabuf_free(data->msgs);
+       data->msgs = wpabuf_dup(msg);
+       if (data->msgs == NULL) {
+               wpabuf_free(msg);
+               return NULL;
+       }
+
+       return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm,
+                                           struct eap_eke_data *data, u8 id)
+{
+       struct wpabuf *msg;
+       u8 pub[EAP_EKE_MAX_DH_LEN];
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Commit");
+
+       if (sm->user == NULL || sm->user->password == NULL) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Password with not configured");
+               eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+               return eap_eke_build_failure(data, id);
+       }
+
+       if (eap_eke_derive_key(&data->sess, sm->user->password,
+                              sm->user->password_len,
+                              sm->server_id, sm->server_id_len,
+                              data->peerid, data->peerid_len, data->key) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return eap_eke_build_failure(data, id);
+       }
+
+       msg = eap_eke_build_msg(data, id, data->sess.dhcomp_len,
+                               EAP_EKE_COMMIT);
+       if (msg == NULL) {
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return eap_eke_build_failure(data, id);
+       }
+
+       /*
+        * y_s = g ^ x_s (mod p)
+        * x_s = random number 2 .. p-1
+        * temp = prf(0+, password)
+        * key = prf+(temp, ID_S | ID_P)
+        * DHComponent_S = Encr(key, y_s)
+        */
+
+       if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return eap_eke_build_failure(data, id);
+       }
+
+       if (eap_eke_dhcomp(&data->sess, data->key, pub,
+                          wpabuf_put(msg, data->sess.dhcomp_len))
+           < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
+               wpabuf_free(msg);
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return eap_eke_build_failure(data, id);
+       }
+
+       if (wpabuf_resize(&data->msgs, wpabuf_len(msg)) < 0) {
+               wpabuf_free(msg);
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return eap_eke_build_failure(data, id);
+       }
+       wpabuf_put_buf(data->msgs, msg);
+
+       return msg;
+}
+
+
+static struct wpabuf * eap_eke_build_confirm(struct eap_sm *sm,
+                                            struct eap_eke_data *data, u8 id)
+{
+       struct wpabuf *msg;
+       size_t plen, prot_len;
+       u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
+       u8 *auth;
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Confirm");
+
+       plen = data->sess.pnonce_ps_len + data->sess.prf_len;
+       msg = eap_eke_build_msg(data, id, plen, EAP_EKE_CONFIRM);
+       if (msg == NULL) {
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return eap_eke_build_failure(data, id);
+       }
+
+       if (random_get_bytes(data->nonce_s, data->sess.nonce_len)) {
+               wpabuf_free(msg);
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return eap_eke_build_failure(data, id);
+       }
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
+                       data->nonce_s, data->sess.nonce_len);
+
+       os_memcpy(nonces, data->nonce_p, data->sess.nonce_len);
+       os_memcpy(nonces + data->sess.nonce_len, data->nonce_s,
+                 data->sess.nonce_len);
+       prot_len = wpabuf_tailroom(msg);
+       if (eap_eke_prot(&data->sess, nonces, 2 * data->sess.nonce_len,
+                        wpabuf_put(msg, 0), &prot_len) < 0) {
+               wpabuf_free(msg);
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return eap_eke_build_failure(data, id);
+       }
+       wpabuf_put(msg, prot_len);
+
+       if (eap_eke_derive_ka(&data->sess,
+                             sm->server_id, sm->server_id_len,
+                             data->peerid, data->peerid_len,
+                             data->nonce_p, data->nonce_s) < 0) {
+               wpabuf_free(msg);
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return eap_eke_build_failure(data, id);
+       }
+
+       auth = wpabuf_put(msg, data->sess.prf_len);
+       if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth) < 0) {
+               wpabuf_free(msg);
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return eap_eke_build_failure(data, id);
+       }
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth, data->sess.prf_len);
+
+       return msg;
+}
+
+
+static struct wpabuf * eap_eke_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+       struct eap_eke_data *data = priv;
+
+       switch (data->state) {
+       case IDENTITY:
+               return eap_eke_build_identity(sm, data, id);
+       case COMMIT:
+               return eap_eke_build_commit(sm, data, id);
+       case CONFIRM:
+               return eap_eke_build_confirm(sm, data, id);
+       case FAILURE_REPORT:
+               return eap_eke_build_failure(data, id);
+       default:
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Unknown state %d in buildReq",
+                          data->state);
+               break;
+       }
+       return NULL;
+}
+
+
+static Boolean eap_eke_check(struct eap_sm *sm, void *priv,
+                            struct wpabuf *respData)
+{
+       struct eap_eke_data *data = priv;
+       size_t len;
+       const u8 *pos;
+       u8 eke_exch;
+
+       pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
+       if (pos == NULL || len < 1) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Invalid frame");
+               return TRUE;
+       }
+
+       eke_exch = *pos;
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: EKE-Exch=%d", eke_exch);
+
+       if (data->state == IDENTITY && eke_exch == EAP_EKE_ID)
+               return FALSE;
+
+       if (data->state == COMMIT && eke_exch == EAP_EKE_COMMIT)
+               return FALSE;
+
+       if (data->state == CONFIRM && eke_exch == EAP_EKE_CONFIRM)
+               return FALSE;
+
+       if (eke_exch == EAP_EKE_FAILURE)
+               return FALSE;
+
+       wpa_printf(MSG_INFO, "EAP-EKE: Unexpected EKE-Exch=%d in state=%d",
+                  eke_exch, data->state);
+
+       return TRUE;
+}
+
+
+static void eap_eke_process_identity(struct eap_sm *sm,
+                                    struct eap_eke_data *data,
+                                    const struct wpabuf *respData,
+                                    const u8 *payload, size_t payloadlen)
+{
+       const u8 *pos, *end;
+       int i;
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Identity");
+
+       if (data->state != IDENTITY) {
+               eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+               return;
+       }
+
+       pos = payload;
+       end = payload + payloadlen;
+
+       if (pos + 2 + 4 + 1 > end) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Too short EAP-EKE-ID payload");
+               eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+               return;
+       }
+
+       if (*pos != 1) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Unexpected NumProposals %d (expected 1)",
+                          *pos);
+               eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+               return;
+       }
+
+       pos += 2;
+
+       if (!supported_proposal(pos)) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Unexpected Proposal (%u:%u:%u:%u)",
+                          pos[0], pos[1], pos[2], pos[3]);
+               eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Selected Proposal (%u:%u:%u:%u)",
+                  pos[0], pos[1], pos[2], pos[3]);
+       if (eap_eke_session_init(&data->sess, pos[0], pos[1], pos[2], pos[3]) <
+           0) {
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return;
+       }
+       pos += 4;
+
+       data->peerid_type = *pos++;
+       os_free(data->peerid);
+       data->peerid = os_malloc(end - pos);
+       if (data->peerid == NULL) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to allocate memory for peerid");
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return;
+       }
+       os_memcpy(data->peerid, pos, end - pos);
+       data->peerid_len = end - pos;
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type);
+       wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity",
+                         data->peerid, data->peerid_len);
+
+       if (eap_user_get(sm, data->peerid, data->peerid_len, data->phase2)) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Peer Identity not found from user database");
+               eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+               return;
+       }
+
+       for (i = 0; i < EAP_MAX_METHODS; i++) {
+               if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
+                   sm->user->methods[i].method == EAP_TYPE_EKE)
+                       break;
+       }
+       if (i == EAP_MAX_METHODS) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Matching user entry does not allow EAP-EKE");
+               eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+               return;
+       }
+
+       if (sm->user->password == NULL || sm->user->password_len == 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: No password configured for peer");
+               eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
+               return;
+       }
+
+       if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return;
+       }
+       wpabuf_put_buf(data->msgs, respData);
+
+       eap_eke_state(data, COMMIT);
+}
+
+
+static void eap_eke_process_commit(struct eap_sm *sm,
+                                  struct eap_eke_data *data,
+                                  const struct wpabuf *respData,
+                                  const u8 *payload, size_t payloadlen)
+{
+       const u8 *pos, *end, *dhcomp, *pnonce;
+       size_t decrypt_len;
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit");
+
+       if (data->state != COMMIT) {
+               eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+               return;
+       }
+
+       pos = payload;
+       end = payload + payloadlen;
+
+       if (pos + data->sess.dhcomp_len + data->sess.pnonce_len > end) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+               eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+               return;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
+                   pos, data->sess.dhcomp_len);
+       dhcomp = pos;
+       pos += data->sess.dhcomp_len;
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len);
+       pnonce = pos;
+       pos += data->sess.pnonce_len;
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
+
+       if (eap_eke_shared_secret(&data->sess, data->key, data->dh_priv, dhcomp)
+           < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return;
+       }
+
+       if (eap_eke_derive_ke_ki(&data->sess,
+                                sm->server_id, sm->server_id_len,
+                                data->peerid, data->peerid_len) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return;
+       }
+
+       decrypt_len = sizeof(data->nonce_p);
+       if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len,
+                                data->nonce_p, &decrypt_len) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_P");
+               eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+               return;
+       }
+       if (decrypt_len < (size_t) data->sess.nonce_len) {
+               wpa_printf(MSG_INFO, "EAP-EKE: PNonce_P protected data too short to include Nonce_P");
+               eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+               return;
+       }
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
+                       data->nonce_p, data->sess.nonce_len);
+
+       if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return;
+       }
+       wpabuf_put_buf(data->msgs, respData);
+
+       eap_eke_state(data, CONFIRM);
+}
+
+
+static void eap_eke_process_confirm(struct eap_sm *sm,
+                                   struct eap_eke_data *data,
+                                   const struct wpabuf *respData,
+                                   const u8 *payload, size_t payloadlen)
+{
+       size_t decrypt_len;
+       u8 nonce[EAP_EKE_MAX_NONCE_LEN];
+       u8 auth_p[EAP_EKE_MAX_HASH_LEN];
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
+
+       if (data->state != CONFIRM) {
+               eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm");
+
+       if (payloadlen < (size_t) data->sess.pnonce_len + data->sess.prf_len) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
+               eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
+               return;
+       }
+
+       decrypt_len = sizeof(nonce);
+       if (eap_eke_decrypt_prot(&data->sess, payload, data->sess.pnonce_len,
+                                nonce, &decrypt_len) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_S");
+               eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+               return;
+       }
+       if (decrypt_len < (size_t) data->sess.nonce_len) {
+               wpa_printf(MSG_INFO, "EAP-EKE: PNonce_S protected data too short to include Nonce_S");
+               eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+               return;
+       }
+       wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_S",
+                       nonce, data->sess.nonce_len);
+       if (os_memcmp(nonce, data->nonce_s, data->sess.nonce_len) != 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_S does not match previously sent Nonce_S");
+               eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+               return;
+       }
+
+       if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth_p) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Could not derive Auth_P");
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return;
+       }
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len);
+       if (os_memcmp(auth_p, payload + data->sess.pnonce_len,
+                     data->sess.prf_len) != 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Auth_P does not match");
+               eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
+               return;
+       }
+
+       if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
+                              data->peerid, data->peerid_len,
+                              data->nonce_s, data->nonce_p,
+                              data->msk, data->emsk) < 0) {
+               wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
+               eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
+               return;
+       }
+
+       os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
+       os_memset(data->key, 0, sizeof(data->key));
+       eap_eke_session_clean(&data->sess);
+
+       eap_eke_state(data, SUCCESS);
+}
+
+
+static void eap_eke_process_failure(struct eap_sm *sm,
+                                   struct eap_eke_data *data,
+                                   const struct wpabuf *respData,
+                                   const u8 *payload, size_t payloadlen)
+{
+       u32 code;
+
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Failure");
+
+       if (payloadlen < 4) {
+               wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
+               eap_eke_state(data, FAILURE);
+               return;
+       }
+
+       code = WPA_GET_BE32(payload);
+       wpa_printf(MSG_DEBUG, "EAP-EKE: Peer reported failure code 0x%x", code);
+
+       eap_eke_state(data, FAILURE);
+}
+
+
+static void eap_eke_process(struct eap_sm *sm, void *priv,
+                            struct wpabuf *respData)
+{
+       struct eap_eke_data *data = priv;
+       u8 eke_exch;
+       size_t len;
+       const u8 *pos, *end;
+
+       pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
+       if (pos == NULL || len < 1)
+               return;
+
+       eke_exch = *pos;
+       end = pos + len;
+       pos++;
+
+       wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received payload", pos, end - pos);
+
+       switch (eke_exch) {
+       case EAP_EKE_ID:
+               eap_eke_process_identity(sm, data, respData, pos, end - pos);
+               break;
+       case EAP_EKE_COMMIT:
+               eap_eke_process_commit(sm, data, respData, pos, end - pos);
+               break;
+       case EAP_EKE_CONFIRM:
+               eap_eke_process_confirm(sm, data, respData, pos, end - pos);
+               break;
+       case EAP_EKE_FAILURE:
+               eap_eke_process_failure(sm, data, respData, pos, end - pos);
+               break;
+       }
+}
+
+
+static Boolean eap_eke_isDone(struct eap_sm *sm, void *priv)
+{
+       struct eap_eke_data *data = priv;
+       return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_eke_data *data = priv;
+       u8 *key;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       key = os_malloc(EAP_MSK_LEN);
+       if (key == NULL)
+               return NULL;
+       os_memcpy(key, data->msk, EAP_MSK_LEN);
+       *len = EAP_MSK_LEN;
+
+       return key;
+}
+
+
+static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_eke_data *data = priv;
+       u8 *key;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       key = os_malloc(EAP_EMSK_LEN);
+       if (key == NULL)
+               return NULL;
+       os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+       *len = EAP_EMSK_LEN;
+
+       return key;
+}
+
+
+static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv)
+{
+       struct eap_eke_data *data = priv;
+       return data->state == SUCCESS;
+}
+
+
+int eap_server_eke_register(void)
+{
+       struct eap_method *eap;
+       int ret;
+
+       eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+                                     EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
+       if (eap == NULL)
+               return -1;
+
+       eap->init = eap_eke_init;
+       eap->reset = eap_eke_reset;
+       eap->buildReq = eap_eke_buildReq;
+       eap->check = eap_eke_check;
+       eap->process = eap_eke_process;
+       eap->isDone = eap_eke_isDone;
+       eap->getKey = eap_eke_getKey;
+       eap->isSuccess = eap_eke_isSuccess;
+       eap->get_emsk = eap_eke_get_emsk;
+
+       ret = eap_server_method_register(eap);
+       if (ret)
+               eap_server_method_free(eap);
+       return ret;
+}
index 2853c48..66f4271 100644 (file)
@@ -26,8 +26,6 @@ struct eap_gpsk_data {
        size_t pk_len;
        u8 *id_peer;
        size_t id_peer_len;
-       u8 *id_server;
-       size_t id_server_len;
 #define MAX_NUM_CSUITES 2
        struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES];
        size_t csuite_count;
@@ -71,11 +69,6 @@ static void * eap_gpsk_init(struct eap_sm *sm)
                return NULL;
        data->state = GPSK_1;
 
-       /* TODO: add support for configuring ID_Server */
-       data->id_server = (u8 *) os_strdup("hostapd");
-       if (data->id_server)
-               data->id_server_len = os_strlen((char *) data->id_server);
-
        data->csuite_count = 0;
        if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
                                           EAP_GPSK_CIPHER_AES)) {
@@ -101,7 +94,6 @@ static void * eap_gpsk_init(struct eap_sm *sm)
 static void eap_gpsk_reset(struct eap_sm *sm, void *priv)
 {
        struct eap_gpsk_data *data = priv;
-       os_free(data->id_server);
        os_free(data->id_peer);
        os_free(data);
 }
@@ -123,7 +115,7 @@ static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
        wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
                    data->rand_server, EAP_GPSK_RAND_LEN);
 
-       len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 +
+       len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 +
                data->csuite_count * sizeof(struct eap_gpsk_csuite);
        req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
                            EAP_CODE_REQUEST, id);
@@ -135,8 +127,8 @@ static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
        }
 
        wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
-       wpabuf_put_be16(req, data->id_server_len);
-       wpabuf_put_data(req, data->id_server, data->id_server_len);
+       wpabuf_put_be16(req, sm->server_id_len);
+       wpabuf_put_data(req, sm->server_id, sm->server_id_len);
        wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
        wpabuf_put_be16(req,
                        data->csuite_count * sizeof(struct eap_gpsk_csuite));
@@ -158,7 +150,7 @@ static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
        wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
 
        miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
-       len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + data->id_server_len +
+       len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len +
                sizeof(struct eap_gpsk_csuite) + 2 + miclen;
        req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
                            EAP_CODE_REQUEST, id);
@@ -174,8 +166,8 @@ static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
 
        wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
        wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
-       wpabuf_put_be16(req, data->id_server_len);
-       wpabuf_put_data(req, data->id_server, data->id_server_len);
+       wpabuf_put_be16(req, sm->server_id_len);
+       wpabuf_put_data(req, sm->server_id, sm->server_id_len);
        csuite = wpabuf_put(req, sizeof(*csuite));
        WPA_PUT_BE32(csuite->vendor, data->vendor);
        WPA_PUT_BE16(csuite->specifier, data->specifier);
@@ -301,8 +293,8 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
                eap_gpsk_state(data, FAILURE);
                return;
        }
-       if (alen != data->id_server_len ||
-           os_memcmp(pos, data->id_server, alen) != 0) {
+       if (alen != sm->server_id_len ||
+           os_memcmp(pos, sm->server_id, alen) != 0) {
                wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
                           "GPSK-2 did not match");
                eap_gpsk_state(data, FAILURE);
@@ -416,7 +408,7 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
                                 data->vendor, data->specifier,
                                 data->rand_peer, data->rand_server,
                                 data->id_peer, data->id_peer_len,
-                                data->id_server, data->id_server_len,
+                                sm->server_id, sm->server_id_len,
                                 data->msk, data->emsk,
                                 data->sk, &data->sk_len,
                                 data->pk, &data->pk_len) < 0) {
index 42aaca2..1ada0c8 100644 (file)
@@ -103,8 +103,11 @@ static void * eap_ikev2_init(struct eap_sm *sm)
        data->ikev2.proposal.encr = ENCR_AES_CBC;
        data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
 
-       data->ikev2.IDi = (u8 *) os_strdup("hostapd");
-       data->ikev2.IDi_len = 7;
+       data->ikev2.IDi = os_malloc(sm->server_id_len);
+       if (data->ikev2.IDi == NULL)
+               goto failed;
+       os_memcpy(data->ikev2.IDi, sm->server_id, sm->server_id_len);
+       data->ikev2.IDi_len = sm->server_id_len;
 
        data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
        data->ikev2.cb_ctx = sm;
index 8d3dd52..3153d2e 100644 (file)
@@ -100,7 +100,6 @@ static struct wpabuf * eap_mschapv2_build_challenge(
 {
        struct wpabuf *req;
        struct eap_mschapv2_hdr *ms;
-       char *name = "hostapd"; /* TODO: make this configurable */
        size_t ms_len;
 
        if (!data->auth_challenge_from_tls &&
@@ -111,7 +110,7 @@ static struct wpabuf * eap_mschapv2_build_challenge(
                return NULL;
        }
 
-       ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + os_strlen(name);
+       ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->server_id_len;
        req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
                            EAP_CODE_REQUEST, id);
        if (req == NULL) {
@@ -133,7 +132,7 @@ static struct wpabuf * eap_mschapv2_build_challenge(
                wpabuf_put(req, CHALLENGE_LEN);
        wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
                    data->auth_challenge, CHALLENGE_LEN);
-       wpabuf_put_data(req, name, os_strlen(name));
+       wpabuf_put_data(req, sm->server_id, sm->server_id_len);
 
        return req;
 }
index 0cd9799..46bedd9 100644 (file)
@@ -22,8 +22,8 @@ struct eap_psk_data {
        enum { PSK_1, PSK_3, SUCCESS, FAILURE } state;
        u8 rand_s[EAP_PSK_RAND_LEN];
        u8 rand_p[EAP_PSK_RAND_LEN];
-       u8 *id_p, *id_s;
-       size_t id_p_len, id_s_len;
+       u8 *id_p;
+       size_t id_p_len;
        u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
        u8 msk[EAP_MSK_LEN];
        u8 emsk[EAP_EMSK_LEN];
@@ -38,8 +38,6 @@ static void * eap_psk_init(struct eap_sm *sm)
        if (data == NULL)
                return NULL;
        data->state = PSK_1;
-       data->id_s = (u8 *) "hostapd";
-       data->id_s_len = 7;
 
        return data;
 }
@@ -70,7 +68,7 @@ static struct wpabuf * eap_psk_build_1(struct eap_sm *sm,
                    data->rand_s, EAP_PSK_RAND_LEN);
 
        req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
-                           sizeof(*psk) + data->id_s_len,
+                           sizeof(*psk) + sm->server_id_len,
                            EAP_CODE_REQUEST, id);
        if (req == NULL) {
                wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
@@ -82,7 +80,7 @@ static struct wpabuf * eap_psk_build_1(struct eap_sm *sm,
        psk = wpabuf_put(req, sizeof(*psk));
        psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
        os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
-       wpabuf_put_data(req, data->id_s, data->id_s_len);
+       wpabuf_put_data(req, sm->server_id, sm->server_id_len);
 
        return req;
 }
@@ -112,13 +110,13 @@ static struct wpabuf * eap_psk_build_3(struct eap_sm *sm,
        os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
 
        /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
-       buflen = data->id_s_len + EAP_PSK_RAND_LEN;
+       buflen = sm->server_id_len + EAP_PSK_RAND_LEN;
        buf = os_malloc(buflen);
        if (buf == NULL)
                goto fail;
 
-       os_memcpy(buf, data->id_s, data->id_s_len);
-       os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
+       os_memcpy(buf, sm->server_id, sm->server_id_len);
+       os_memcpy(buf + sm->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
        if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
                os_free(buf);
                goto fail;
@@ -296,7 +294,7 @@ static void eap_psk_process_2(struct eap_sm *sm,
        os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
 
        /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
-       buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
+       buflen = data->id_p_len + sm->server_id_len + 2 * EAP_PSK_RAND_LEN;
        buf = os_malloc(buflen);
        if (buf == NULL) {
                data->state = FAILURE;
@@ -304,8 +302,8 @@ static void eap_psk_process_2(struct eap_sm *sm,
        }
        os_memcpy(buf, data->id_p, data->id_p_len);
        pos = buf + data->id_p_len;
-       os_memcpy(pos, data->id_s, data->id_s_len);
-       pos += data->id_s_len;
+       os_memcpy(pos, sm->server_id, sm->server_id_len);
+       pos += sm->server_id_len;
        os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
        pos += EAP_PSK_RAND_LEN;
        os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
index f72e1bf..68dd76b 100644 (file)
@@ -27,8 +27,6 @@ struct eap_sake_data {
        u8 session_id;
        u8 *peerid;
        size_t peerid_len;
-       u8 *serverid;
-       size_t serverid_len;
 };
 
 
@@ -77,11 +75,6 @@ static void * eap_sake_init(struct eap_sm *sm)
        wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
                   data->session_id);
 
-       /* TODO: add support for configuring SERVERID */
-       data->serverid = (u8 *) os_strdup("hostapd");
-       if (data->serverid)
-               data->serverid_len = os_strlen((char *) data->serverid);
-
        return data;
 }
 
@@ -89,7 +82,6 @@ static void * eap_sake_init(struct eap_sm *sm)
 static void eap_sake_reset(struct eap_sm *sm, void *priv)
 {
        struct eap_sake_data *data = priv;
-       os_free(data->serverid);
        os_free(data->peerid);
        os_free(data);
 }
@@ -131,8 +123,7 @@ static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
        wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
 
        plen = 4;
-       if (data->serverid)
-               plen += 2 + data->serverid_len;
+       plen += 2 + sm->server_id_len;
        msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
        if (msg == NULL) {
                data->state = FAILURE;
@@ -142,11 +133,9 @@ static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
        wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
        eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
 
-       if (data->serverid) {
-               wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
-               eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
-                                 data->serverid, data->serverid_len);
-       }
+       wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+       eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
+                         sm->server_id, sm->server_id_len);
 
        return msg;
 }
@@ -169,9 +158,7 @@ static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
        wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
                    data->rand_s, EAP_SAKE_RAND_LEN);
 
-       plen = 2 + EAP_SAKE_RAND_LEN;
-       if (data->serverid)
-               plen += 2 + data->serverid_len;
+       plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->server_id_len;
        msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
        if (msg == NULL) {
                data->state = FAILURE;
@@ -182,11 +169,9 @@ static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
        eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
                          data->rand_s, EAP_SAKE_RAND_LEN);
 
-       if (data->serverid) {
-               wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
-               eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
-                                 data->serverid, data->serverid_len);
-       }
+       wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+       eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
+                         sm->server_id, sm->server_id_len);
 
        return msg;
 }
@@ -213,7 +198,7 @@ static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
        wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
        mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
        if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-                                data->serverid, data->serverid_len,
+                                sm->server_id, sm->server_id_len,
                                 data->peerid, data->peerid_len, 0,
                                 wpabuf_head(msg), wpabuf_len(msg), mic, mic))
        {
@@ -362,7 +347,7 @@ static void eap_sake_process_challenge(struct eap_sm *sm,
                             (u8 *) &data->tek, data->msk, data->emsk);
 
        eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-                            data->serverid, data->serverid_len,
+                            sm->server_id, sm->server_id_len,
                             data->peerid, data->peerid_len, 1,
                             wpabuf_head(respData), wpabuf_len(respData),
                             attr.mic_p, mic_p);
@@ -399,7 +384,7 @@ static void eap_sake_process_confirm(struct eap_sm *sm,
        }
 
        eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-                            data->serverid, data->serverid_len,
+                            sm->server_id, sm->server_id_len,
                             data->peerid, data->peerid_len, 1,
                             wpabuf_head(respData), wpabuf_len(respData),
                             attr.mic_p, mic_p);
index c3ccb46..013d781 100644 (file)
@@ -830,6 +830,8 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
        eap_conf.fragment_size = eapol->conf.fragment_size;
        eap_conf.pwd_group = eapol->conf.pwd_group;
        eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
+       eap_conf.server_id = eapol->conf.server_id;
+       eap_conf.server_id_len = eapol->conf.server_id_len;
        sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
        if (sm->eap == NULL) {
                eapol_auth_free(sm);
@@ -1045,6 +1047,8 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
        os_free(dst->eap_req_id_text);
        dst->pwd_group = src->pwd_group;
        dst->pbc_in_m1 = src->pbc_in_m1;
+       dst->server_id = src->server_id;
+       dst->server_id_len = src->server_id_len;
        if (src->eap_req_id_text) {
                dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
                if (dst->eap_req_id_text == NULL)
index b50bbdd..3a0f450 100644 (file)
@@ -37,6 +37,8 @@ struct eapol_auth_config {
        int fragment_size;
        u16 pwd_group;
        int pbc_in_m1;
+       const u8 *server_id;
+       size_t server_id_len;
 
        /* Opaque context pointer to owner data for callback functions */
        void *ctx;
index 0534b8c..0a414ee 100644 (file)
@@ -1967,39 +1967,6 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
 }
 
 
-static int is_11b(u8 rate)
-{
-       return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
-}
-
-
-static int supp_rates_11b_only(struct ieee802_11_elems *elems)
-{
-       int num_11b = 0, num_others = 0;
-       int i;
-
-       if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
-               return 0;
-
-       for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
-               if (is_11b(elems->supp_rates[i]))
-                       num_11b++;
-               else
-                       num_others++;
-       }
-
-       for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
-            i++) {
-               if (is_11b(elems->ext_supp_rates[i]))
-                       num_11b++;
-               else
-                       num_others++;
-       }
-
-       return num_11b > 0 && num_others == 0;
-}
-
-
 static enum p2p_probe_req_status
 p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
                const u8 *bssid, const u8 *ie, size_t ie_len)
index 5b2d711..0144c9f 100644 (file)
@@ -223,6 +223,11 @@ struct radius_server_data {
        u16 pwd_group;
 
        /**
+        * server_id - Server identity
+        */
+       const char *server_id;
+
+       /**
         * wps - Wi-Fi Protected Setup context
         *
         * If WPS is used with an external RADIUS server (which is quite
@@ -511,6 +516,8 @@ radius_server_get_new_session(struct radius_server_data *data,
        eap_conf.tnc = data->tnc;
        eap_conf.wps = data->wps;
        eap_conf.pwd_group = data->pwd_group;
+       eap_conf.server_id = (const u8 *) data->server_id;
+       eap_conf.server_id_len = os_strlen(data->server_id);
        sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
                                       &eap_conf);
        if (sess->eap == NULL) {
@@ -1280,6 +1287,7 @@ radius_server_init(struct radius_server_conf *conf)
        data->tnc = conf->tnc;
        data->wps = conf->wps;
        data->pwd_group = conf->pwd_group;
+       data->server_id = conf->server_id;
        if (conf->eap_req_id_text) {
                data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
                if (data->eap_req_id_text) {
index 82466c3..284bd59 100644 (file)
@@ -144,6 +144,11 @@ struct radius_server_conf {
        u16 pwd_group;
 
        /**
+        * server_id - Server identity
+        */
+       const char *server_id;
+
+       /**
         * wps - Wi-Fi Protected Setup context
         *
         * If WPS is used with an external RADIUS server (which is quite
index 93056ea..33fa1a2 100644 (file)
@@ -15,7 +15,7 @@
 #include "wpa_i.h"
 #include "pmksa_cache.h"
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 static const int pmksa_cache_max_entries = 32;
 
@@ -522,4 +522,4 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
        return pmksa;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
index d5aa229..6cbf89a 100644 (file)
@@ -44,7 +44,7 @@ enum pmksa_free_reason {
        PMKSA_EXPIRE,
 };
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
@@ -69,7 +69,7 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
 void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
                       const u8 *pmk, size_t pmk_len);
 
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
 
 static inline struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
@@ -122,10 +122,11 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
 }
 
 static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
-                                    void *network_ctx)
+                                    void *network_ctx,
+                                    const u8 *pmk, size_t pmk_len)
 {
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
 
 #endif /* PMKSA_CACHE_H */
index ab61867..c51620e 100644 (file)
@@ -18,7 +18,7 @@
 #include "wpa_i.h"
 
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 #define PMKID_CANDIDATE_PRIO_SCAN 1000
 
@@ -508,4 +508,4 @@ int rsn_preauth_in_progress(struct wpa_sm *sm)
        return sm->preauth_eapol != NULL;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
index 27d3112..277f066 100644 (file)
@@ -11,7 +11,7 @@
 
 struct wpa_scan_results;
 
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
 
 void pmksa_candidate_free(struct wpa_sm *sm);
 int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
@@ -27,7 +27,7 @@ int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
                           int verbose);
 int rsn_preauth_in_progress(struct wpa_sm *sm);
 
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
 
 static inline void pmksa_candidate_free(struct wpa_sm *sm)
 {
@@ -74,6 +74,6 @@ static inline int rsn_preauth_in_progress(struct wpa_sm *sm)
        return 0;
 }
 
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
 
 #endif /* PREAUTH_H */
index 221d5fd..539aa25 100644 (file)
@@ -1347,7 +1347,8 @@ static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde,
        peer->supp_rates_len = merge_byte_arrays(
                peer->supp_rates, sizeof(peer->supp_rates),
                kde->supp_rates + 2, kde->supp_rates_len - 2,
-               kde->ext_supp_rates + 2, kde->ext_supp_rates_len - 2);
+               kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL,
+               kde->ext_supp_rates_len - 2);
        return 0;
 }
 
index d83700a..292255c 100644 (file)
@@ -392,7 +392,6 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
 
        os_memset(&ie, 0, sizeof(ie));
 
-#ifndef CONFIG_NO_WPA2
        if (sm->proto == WPA_PROTO_RSN) {
                /* RSN: msg 1/4 should contain PMKID for the selected PMK */
                const u8 *_buf = (const u8 *) (key + 1);
@@ -405,7 +404,6 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
                                    "Authenticator", ie.pmkid, PMKID_LEN);
                }
        }
-#endif /* CONFIG_NO_WPA2 */
 
        res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
        if (res == -2) {
@@ -664,7 +662,6 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
                                       const u8 *gtk, size_t gtk_len,
                                       int key_info)
 {
-#ifndef CONFIG_NO_WPA2
        struct wpa_gtk_data gd;
 
        /*
@@ -703,9 +700,6 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
        wpa_supplicant_key_neg_complete(sm, sm->bssid,
                                        key_info & WPA_KEY_INFO_SECURE);
        return 0;
-#else /* CONFIG_NO_WPA2 */
-       return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
@@ -2601,11 +2595,7 @@ int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data)
 
 int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
 {
-#ifndef CONFIG_NO_WPA2
        return pmksa_cache_list(sm->pmksa, buf, len);
-#else /* CONFIG_NO_WPA2 */
-       return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
@@ -2636,9 +2626,7 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
 
 void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
 {
-#ifndef CONFIG_NO_WPA2
        pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
index c757dcf..26e9c6c 100644 (file)
@@ -245,6 +245,11 @@ static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf,
        return 0;
 }
 
+static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
+{
+       return 0;
+}
+
 static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
                                      int pairwise)
 {
index ba203e6..50b9272 100644 (file)
@@ -107,7 +107,6 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
                              int key_mgmt, int mgmt_group_cipher,
                              struct wpa_sm *sm)
 {
-#ifndef CONFIG_NO_WPA2
        u8 *pos;
        struct rsn_ie_hdr *hdr;
        u16 capab;
@@ -220,9 +219,6 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
        WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
 
        return pos - rsn_ie;
-#else /* CONFIG_NO_WPA2 */
-       return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
index f947388..c6f4e43 100644 (file)
 #endif /* USE_INTERNAL_CRYPTO */
 #endif /* CONFIG_WIN32_DEFAULTS */
 
-#ifdef CONFIG_XCODE_DEFAULTS
-#define CONFIG_DRIVER_OSX
-#define CONFIG_BACKEND_FILE
-#define IEEE8021X_EAPOL
-#define PKCS12_FUNCS
-#define CONFIG_CTRL_IFACE
-#define CONFIG_CTRL_IFACE_UNIX
-#define CONFIG_DEBUG_FILE
-#define EAP_MD5
-#define EAP_TLS
-#define EAP_MSCHAPv2
-#define EAP_PEAP
-#define EAP_TTLS
-#define EAP_GTC
-#define EAP_OTP
-#define EAP_LEAP
-#define EAP_TNC
-#define CONFIG_WPS
-#define EAP_WSC
-
-#ifdef USE_INTERNAL_CRYPTO
-#define CONFIG_TLS_INTERNAL_CLIENT
-#define CONFIG_INTERNAL_LIBTOMMATH
-#define CONFIG_CRYPTO_INTERNAL
-#endif /* USE_INTERNAL_CRYPTO */
-#endif /* CONFIG_XCODE_DEFAULTS */
-
 #endif /* BUILD_CONFIG_H */
index af63e4d..bea2b33 100644 (file)
@@ -982,6 +982,7 @@ static void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
 
        wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device");
        web_listener_stop(sm);
+       ssdp_listener_stop(sm);
        upnp_wps_free_msearchreply(&sm->msearch_replies);
        upnp_wps_free_subscriptions(&sm->subscriptions, NULL);
 
@@ -995,7 +996,6 @@ static void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
        if (sm->multicast_sd >= 0)
                close(sm->multicast_sd);
        sm->multicast_sd = -1;
-       ssdp_listener_stop(sm);
 
        sm->started = 0;
 }
index a0c97f0..8515b5a 100644 (file)
@@ -236,7 +236,7 @@ NEED_SHA1=y
 NEED_MD5=y
 NEED_RC4=y
 else
-L_CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+L_CFLAGS += -DCONFIG_NO_WPA
 endif
 
 ifdef CONFIG_IBSS_RSN
@@ -286,10 +286,6 @@ L_CFLAGS += -DCONFIG_INTERWORKING
 NEED_GAS=y
 endif
 
-ifdef CONFIG_NO_WPA2
-L_CFLAGS += -DCONFIG_NO_WPA2
-endif
-
 include $(LOCAL_PATH)/src/drivers/drivers.mk
 
 ifdef CONFIG_AP
@@ -601,6 +597,22 @@ CONFIG_IEEE8021X_EAPOL=y
 NEED_SHA256=y
 endif
 
+ifdef CONFIG_EAP_EKE
+# EAP-EKE
+ifeq ($(CONFIG_EAP_EKE), dyn)
+L_CFLAGS += -DEAP_EKE_DYNAMIC
+EAPDYN += src/eap_peer/eap_eke.so
+else
+L_CFLAGS += -DEAP_EKE
+OBJS += src/eap_peer/eap_eke.c src/eap_common/eap_eke_common.c
+OBJS_h += src/eap_server/eap_server_eke.c
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_SHA256=y
+endif
+
 ifdef CONFIG_WPS
 ifdef CONFIG_WPS2
 L_CFLAGS += -DCONFIG_WPS2
index 0634219..5698619 100644 (file)
@@ -215,7 +215,7 @@ NEED_SHA1=y
 NEED_MD5=y
 NEED_RC4=y
 else
-CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+CFLAGS += -DCONFIG_NO_WPA
 endif
 
 ifdef CONFIG_IBSS_RSN
@@ -265,10 +265,6 @@ CFLAGS += -DCONFIG_INTERWORKING
 NEED_GAS=y
 endif
 
-ifdef CONFIG_NO_WPA2
-CFLAGS += -DCONFIG_NO_WPA2
-endif
-
 include ../src/drivers/drivers.mak
 ifdef CONFIG_AP
 OBJS_d += $(DRV_BOTH_OBJS)
@@ -579,6 +575,22 @@ CONFIG_IEEE8021X_EAPOL=y
 NEED_SHA256=y
 endif
 
+ifdef CONFIG_EAP_EKE
+# EAP-EKE
+ifeq ($(CONFIG_EAP_EKE), dyn)
+CFLAGS += -DEAP_EKE_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_eke.so
+else
+CFLAGS += -DEAP_EKE
+OBJS += ../src/eap_peer/eap_eke.o ../src/eap_common/eap_eke_common.o
+OBJS_h += ../src/eap_server/eap_server_eke.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_SHA256=y
+endif
+
 ifdef CONFIG_WPS
 ifdef CONFIG_WPS2
 CFLAGS += -DCONFIG_WPS2
@@ -1581,6 +1593,10 @@ eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_com
        $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
                -Deap_peer_ikev2_register=eap_peer_method_dynamic_init
 
+eap_eke.so: ../src/eap_peer/eap_eke.c ../src/eap_common/eap_eke_common.c
+       $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+               -Deap_peer_eke_register=eap_peer_method_dynamic_init
+
 %.so: %.c
        $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
                -D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
index 331940c..8b3d6b4 100644 (file)
@@ -262,11 +262,6 @@ CONFIG_WPA_CLI_EDIT=y
 # 35-50 kB in code size.
 #CONFIG_NO_WPA=y
 
-# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
-# save about 1 kB in code size when building only WPA-Personal (no EAP support)
-# or 6 kB if building for WPA-Enterprise.
-#CONFIG_NO_WPA2=y
-
 # Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
 # This option can be used to reduce code size by removing support for
 # converting ASCII passphrases into PSK. If this functionality is removed, the
index d9e1f82..c48a286 100644 (file)
@@ -124,7 +124,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_P2P
-       if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+       if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
+           (ssid->mode == WPAS_MODE_P2P_GO ||
+            ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)) {
                /* Remove 802.11b rates from supported and basic rate sets */
                int *list = os_malloc(4 * sizeof(int));
                if (list) {
@@ -492,6 +494,11 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
 
        if (wpa_drv_associate(wpa_s, &params) < 0) {
                wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
+#ifdef CONFIG_P2P
+               if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION &&
+                   wpa_s->global->p2p_group_formation == wpa_s)
+                       wpas_p2p_group_formation_failed(wpa_s->parent);
+#endif /* CONFIG_P2P */
                return -1;
        }
 
index 7a860b6..a35be51 100644 (file)
@@ -1522,6 +1522,7 @@ static const struct parse_data ssid_fields[] = {
        { INT(eap_workaround) },
        { STRe(pac_file) },
        { INTe(fragment_size) },
+       { INTe(ocsp) },
 #endif /* IEEE8021X_EAPOL */
        { INT_RANGE(mode, 0, 4) },
        { INT_RANGE(proactive_key_caching, 0, 1) },
index a354a11..a24abaf 100644 (file)
@@ -5018,23 +5018,76 @@ static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd
 #endif /* CONFIG_WNM */
 
 
+/* Get string representation of channel width */
+static const char * channel_width_name(enum chan_width width)
+{
+       switch (width) {
+       case CHAN_WIDTH_20_NOHT:
+               return "20 MHz (no HT)";
+       case CHAN_WIDTH_20:
+               return "20 MHz";
+       case CHAN_WIDTH_40:
+               return "40 MHz";
+       case CHAN_WIDTH_80:
+               return "80 MHz";
+       case CHAN_WIDTH_80P80:
+               return "80+80 MHz";
+       case CHAN_WIDTH_160:
+               return "160 MHz";
+       default:
+               return "unknown";
+       }
+}
+
+
 static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
                                      size_t buflen)
 {
        struct wpa_signal_info si;
        int ret;
+       char *pos, *end;
 
        ret = wpa_drv_signal_poll(wpa_s, &si);
        if (ret)
                return -1;
 
-       ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
+       pos = buf;
+       end = buf + buflen;
+
+       ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
                          "NOISE=%d\nFREQUENCY=%u\n",
                          si.current_signal, si.current_txrate / 1000,
                          si.current_noise, si.frequency);
-       if (ret < 0 || (unsigned int) ret > buflen)
+       if (ret < 0 || ret > end - pos)
                return -1;
-       return ret;
+       pos += ret;
+
+       if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
+               ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
+                                 channel_width_name(si.chanwidth));
+               if (ret < 0 || ret > end - pos)
+                       return -1;
+               pos += ret;
+       }
+
+       if (si.center_frq1 > 0 && si.center_frq2 > 0) {
+               ret = os_snprintf(pos, end - pos,
+                                 "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
+                                 si.center_frq1, si.center_frq2);
+               if (ret < 0 || ret > end - pos)
+                       return -1;
+               pos += ret;
+       }
+
+       if (si.avg_signal) {
+               ret = os_snprintf(pos, end - pos,
+                                 "AVG_RSSI=%d\n", si.avg_signal);
+               if (ret < 0 || ret >= end - pos)
+                       return -1;
+               pos += ret;
+       }
+
+       return pos - buf;
 }
 
 
index 1b4b9b0..fc0d649 100644 (file)
@@ -602,7 +602,7 @@ static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
                                    offsetof(struct sockaddr_un, sun_path));
                        msg.msg_name = (void *) &dst->addr;
                        msg.msg_namelen = dst->addrlen;
-                       if (sendmsg(sock, &msg, 0) < 0) {
+                       if (sendmsg(sock, &msg, MSG_DONTWAIT) < 0) {
                                int _errno = errno;
                                wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
                                           "%d - %s",
index e9bd51f..ddd2c82 100644 (file)
@@ -869,6 +869,76 @@ nomem:
 }
 
 
+/**
+ * wpas_dbus_signal_sta - Send a station related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ * @sig_name: signal name - StaAuthorized or StaDeauthorized
+ *
+ * Notify listeners about event related with station
+ */
+static void wpas_dbus_signal_sta(struct wpa_supplicant *wpa_s,
+                                const u8 *sta, const char *sig_name)
+{
+       struct wpas_dbus_priv *iface;
+       DBusMessage *msg;
+       char sta_mac[WPAS_DBUS_OBJECT_PATH_MAX];
+       char *dev_mac;
+
+       os_snprintf(sta_mac, WPAS_DBUS_OBJECT_PATH_MAX, MACSTR, MAC2STR(sta));
+       dev_mac = sta_mac;
+
+       iface = wpa_s->global->dbus;
+
+       /* Do nothing if the control interface is not turned on */
+       if (iface == NULL)
+               return;
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name);
+       if (msg == NULL)
+               return;
+
+       if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &dev_mac,
+                                    DBUS_TYPE_INVALID))
+               dbus_connection_send(iface->con, msg, NULL);
+       else
+               wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+       dbus_message_unref(msg);
+
+       wpa_printf(MSG_DEBUG, "dbus: Station MAC address '%s' '%s'",
+                  sta_mac, sig_name);
+}
+
+
+/**
+ * wpas_dbus_signal_sta_authorized - Send a STA authorized signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ *
+ * Notify listeners a new station has been authorized
+ */
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+                                    const u8 *sta)
+{
+       wpas_dbus_signal_sta(wpa_s, sta, "StaAuthorized");
+}
+
+
+/**
+ * wpas_dbus_signal_sta_deauthorized - Send a STA deauthorized signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sta: station mac address
+ *
+ * Notify listeners a station has been deauthorized
+ */
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+                                      const u8 *sta)
+{
+       wpas_dbus_signal_sta(wpa_s, sta, "StaDeauthorized");
+}
+
+
 #ifdef CONFIG_P2P
 
 /**
@@ -1920,15 +1990,6 @@ static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
                  END_ARGS
          }
        },
-#ifdef CONFIG_AUTOSCAN
-       { "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
-         (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
-         {
-                 { "arg", "s", ARG_IN },
-                 END_ARGS
-         }
-       },
-#endif /* CONFIG_AUTOSCAN */
        { NULL, NULL, NULL, { END_ARGS } }
 };
 
@@ -2666,6 +2727,15 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
                  END_ARGS
          }
        },
+#ifdef CONFIG_AUTOSCAN
+       { "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
+         {
+                 { "arg", "s", ARG_IN },
+                 END_ARGS
+         }
+       },
+#endif /* CONFIG_AUTOSCAN */
        { NULL, NULL, NULL, { END_ARGS } }
 };
 
@@ -3017,6 +3087,18 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
                  END_ARGS
          }
        },
+       { "StaAuthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "name", "s", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "StaDeauthorized", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         {
+                 { "name", "s", ARG_OUT },
+                 END_ARGS
+         }
+       },
        { NULL, NULL, { END_ARGS } }
 };
 
index 363a7e5..61c480a 100644 (file)
@@ -222,6 +222,10 @@ void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
                           const u8 *ie, size_t ie_len, u32 ssi_signal);
 void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
                                 const char *status, const char *parameter);
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+                                    const u8 *sta);
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+                                      const u8 *sta);
 
 #else /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
@@ -493,6 +497,18 @@ static inline void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
 {
 }
 
+static inline
+void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s,
+                                    const u8 *sta)
+{
+}
+
+static inline
+void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s,
+                                      const u8 *sta)
+{
+}
+
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
 #endif /* CTRL_IFACE_DBUS_H_NEW */
index 5663a5f..aa6005f 100644 (file)
@@ -210,6 +210,9 @@ CONFIG_EAP_LEAP=y
 # EAP-IKEv2
 #CONFIG_EAP_IKEV2=y
 
+# EAP-EKE
+#CONFIG_EAP_EKE=y
+
 # PKCS#12 (PFX) support (used to read private key and certificate file from
 # a file that usually has extension .p12 or .pfx)
 CONFIG_PKCS12=y
@@ -261,11 +264,6 @@ CONFIG_CTRL_IFACE=y
 # 35-50 kB in code size.
 #CONFIG_NO_WPA=y
 
-# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
-# save about 1 kB in code size when building only WPA-Personal (no EAP support)
-# or 6 kB if building for WPA-Enterprise.
-#CONFIG_NO_WPA2=y
-
 # Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
 # This option can be used to reduce code size by removing support for
 # converting ASCII passphrases into PSK. If this functionality is removed, the
index 6bab19c..9922e07 100644 (file)
@@ -129,6 +129,16 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
        return -1;
 }
 
+static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s,
+                                    const u8 *addr, int reason_code)
+{
+       if (wpa_s->driver->sta_deauth) {
+               return wpa_s->driver->sta_deauth(wpa_s->drv_priv, NULL, addr,
+                                                reason_code);
+       }
+       return -1;
+}
+
 static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
                                         const u8 *addr, int reason_code)
 {
index d1eb4ff..6cd2fc5 100644 (file)
@@ -135,6 +135,11 @@ int eap_register_methods(void)
                ret = eap_peer_pwd_register();
 #endif /* EAP_PWD */
 
+#ifdef EAP_EKE
+       if (ret == 0)
+               ret = eap_peer_eke_register();
+#endif /* EAP_EKE */
+
 #ifdef EAP_SERVER_IDENTITY
        if (ret == 0)
                ret = eap_server_identity_register();
index 60e71b6..d39216f 100644 (file)
 #include "interworking.h"
 
 
+#ifndef CONFIG_NO_SCAN_PROCESSING
 static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
                                              int new_scan);
+#endif /* CONFIG_NO_SCAN_PROCESSING */
 
 
 static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
@@ -1957,7 +1959,9 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
        int authenticating;
        u8 prev_pending_bssid[ETH_ALEN];
        struct wpa_bss *fast_reconnect = NULL;
+#ifndef CONFIG_NO_SCAN_PROCESSING
        struct wpa_ssid *fast_reconnect_ssid = NULL;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
        struct wpa_ssid *last_ssid;
 
        authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
@@ -1998,7 +2002,9 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
                         * time for some common cases.
                         */
                        fast_reconnect = wpa_s->current_bss;
+#ifndef CONFIG_NO_SCAN_PROCESSING
                        fast_reconnect_ssid = wpa_s->current_ssid;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
                } else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
 #ifdef ANDROID
                        wpa_supplicant_req_scan(wpa_s, 0, 500000);
index 046f181..687c042 100644 (file)
@@ -296,6 +296,13 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 }
 
 
+static void ibss_rsn_disconnect(void *ctx, const u8 *addr, u16 reason)
+{
+       struct ibss_rsn *ibss_rsn = ctx;
+       wpa_drv_sta_deauth(ibss_rsn->wpa_s, addr, reason);
+}
+
+
 static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm,
                                                  void *ctx),
                             void *cb_ctx)
@@ -386,6 +393,7 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
        cb.get_psk = auth_get_psk;
        cb.set_key = auth_set_key;
        cb.for_each_sta = auth_for_each_sta;
+       cb.disconnect = ibss_rsn_disconnect;
 
        ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb);
        if (ibss_rsn->auth_group == NULL) {
index e35628b..36f75a1 100644 (file)
@@ -599,19 +599,29 @@ static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
 
 static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
 {
-       u8 plmn[3];
+       u8 plmn[3], plmn2[3];
        const u8 *pos, *end;
        u8 udhl;
 
-       /* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
+       /*
+        * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network
+        * operator is allowed to include only two digits of the MNC, so allow
+        * matches based on both two and three digit MNC assumptions. Since some
+        * SIM/USIM cards may not expose MNC length conveniently, we may be
+        * provided the default MNC length 3 here and as such, checking with MNC
+        * length 2 is justifiable even though 3GPP TS 24.234 does not mention
+        * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used
+        * with otherwise matching values would not be good idea in general, so
+        * this should not result in selecting incorrect networks.
+        */
+       /* Match with 3 digit MNC */
        plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
-       plmn[1] = imsi[2] - '0';
-       /* default to MNC length 3 if unknown */
-       if (mnc_len != 2)
-               plmn[1] |= (imsi[5] - '0') << 4;
-       else
-               plmn[1] |= 0xf0;
+       plmn[1] = (imsi[2] - '0') | ((imsi[5] - '0') << 4);
        plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
+       /* Match with 2 digit MNC */
+       plmn2[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
+       plmn2[1] = (imsi[2] - '0') | 0xf0;
+       plmn2[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
 
        if (anqp == NULL)
                return 0;
@@ -631,6 +641,10 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
        }
        end = pos + udhl;
 
+       wpa_printf(MSG_DEBUG, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)",
+                  plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
+                  imsi, mnc_len);
+
        while (pos + 2 <= end) {
                u8 iei, len;
                const u8 *l_end;
@@ -643,14 +657,20 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
                if (iei == 0 && len > 0) {
                        /* PLMN List */
                        u8 num, i;
+                       wpa_hexdump(MSG_DEBUG, "Interworking: PLMN List information element",
+                                   pos, len);
                        num = *pos++;
                        for (i = 0; i < num; i++) {
-                               if (pos + 3 > end)
+                               if (pos + 3 > l_end)
                                        break;
-                               if (os_memcmp(pos, plmn, 3) == 0)
+                               if (os_memcmp(pos, plmn, 3) == 0 ||
+                                   os_memcmp(pos, plmn2, 3) == 0)
                                        return 1; /* Found matching PLMN */
                                pos += 3;
                        }
+               } else {
+                       wpa_hexdump(MSG_DEBUG, "Interworking: Unrecognized 3GPP information element",
+                                   pos, len);
                }
 
                pos = l_end;
@@ -1337,6 +1357,8 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
                char *sep;
                const char *imsi;
                int mnc_len;
+               char imsi_buf[16];
+               size_t msin_len;
 
 #ifdef PCSC_FUNCS
                if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
@@ -1346,6 +1368,13 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
                        goto compare;
                }
 #endif /* PCSC_FUNCS */
+#ifdef CONFIG_EAP_PROXY
+               if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+                       imsi = wpa_s->imsi;
+                       mnc_len = wpa_s->mnc_len;
+                       goto compare;
+               }
+#endif /* CONFIG_EAP_PROXY */
 
                if (cred->imsi == NULL || !cred->imsi[0] ||
                    cred->milenage == NULL || !cred->milenage[0])
@@ -1356,11 +1385,18 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
                    (sep - cred->imsi != 5 && sep - cred->imsi != 6))
                        continue;
                mnc_len = sep - cred->imsi - 3;
-               imsi = cred->imsi;
-
-#ifdef PCSC_FUNCS
+               os_memcpy(imsi_buf, cred->imsi, 3 + mnc_len);
+               sep++;
+               msin_len = os_strlen(cred->imsi);
+               if (3 + mnc_len + msin_len >= sizeof(imsi_buf) - 1)
+                       msin_len = sizeof(imsi_buf) - 3 - mnc_len - 1;
+               os_memcpy(&imsi_buf[3 + mnc_len], sep, msin_len);
+               imsi_buf[3 + mnc_len + msin_len] = '\0';
+               imsi = imsi_buf;
+
+#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
        compare:
-#endif /* PCSC_FUNCS */
+#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
                wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
                           MACSTR, MAC2STR(bss->bssid));
                ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
index 1b3364c..39b837e 100644 (file)
@@ -14,6 +14,7 @@
 #include "common.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
+#include "p2p_supplicant.h"
 
 extern struct wpa_driver_ops *wpa_drivers[];
 
@@ -289,6 +290,8 @@ int main(int argc, char *argv[])
        }
 
        for (i = 0; exitcode == 0 && i < iface_count; i++) {
+               struct wpa_supplicant *wpa_s;
+
                if ((ifaces[i].confname == NULL &&
                     ifaces[i].ctrl_interface == NULL) ||
                    ifaces[i].ifname == NULL) {
@@ -299,8 +302,18 @@ int main(int argc, char *argv[])
                        exitcode = -1;
                        break;
                }
-               if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+               wpa_s = wpa_supplicant_add_iface(global, &ifaces[i]);
+               if (wpa_s == NULL) {
+                       exitcode = -1;
+                       break;
+               }
+#ifdef CONFIG_P2P
+               if (wpa_s->global->p2p == NULL &&
+                   (wpa_s->drv_flags &
+                    WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+                   wpas_p2p_add_p2pdev_interface(wpa_s) < 0)
                        exitcode = -1;
+#endif /* CONFIG_P2P */
        }
 
        if (exitcode == 0)
index 3ed826d..f2cbdd7 100644 (file)
@@ -551,6 +551,9 @@ static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
         */
        wpas_dbus_signal_p2p_peer_joined(wpa_s, sta);
 #endif /* CONFIG_P2P */
+
+       /* Notify listeners a new station has been authorized */
+       wpas_dbus_signal_sta_authorized(wpa_s, sta);
 }
 
 
@@ -570,6 +573,9 @@ static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s,
         */
        wpas_dbus_signal_p2p_peer_disconnected(wpa_s, sta);
 #endif /* CONFIG_P2P */
+
+       /* Notify listeners a station has been deauthorized */
+       wpas_dbus_signal_sta_deauthorized(wpa_s, sta);
 }
 
 
index f9193ae..37f5ad3 100644 (file)
@@ -65,6 +65,8 @@
 #define P2P_CONCURRENT_SEARCH_DELAY 500
 #endif /* P2P_CONCURRENT_SEARCH_DELAY */
 
+#define P2P_MGMT_DEVICE_PREFIX         "p2p-dev-"
+
 enum p2p_group_removal_reason {
        P2P_GROUP_REMOVAL_UNKNOWN,
        P2P_GROUP_REMOVAL_SILENT,
@@ -1013,6 +1015,26 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
 }
 
 
+static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s,
+                                     char *ifname, size_t len)
+{
+       char *ifname_ptr = wpa_s->ifname;
+
+       if (os_strncmp(wpa_s->ifname, P2P_MGMT_DEVICE_PREFIX,
+                      os_strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+               ifname_ptr = os_strrchr(wpa_s->ifname, '-') + 1;
+       }
+
+       os_snprintf(ifname, len, "p2p-%s-%d", ifname_ptr, wpa_s->p2p_group_idx);
+       if (os_strlen(ifname) >= IFNAMSIZ &&
+           os_strlen(wpa_s->ifname) < IFNAMSIZ) {
+               /* Try to avoid going over the IFNAMSIZ length limit */
+               os_snprintf(ifname, sizeof(ifname), "p2p-%d",
+                           wpa_s->p2p_group_idx);
+       }
+}
+
+
 static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
                                        enum wpa_driver_if_type type)
 {
@@ -1030,14 +1052,7 @@ static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
                return 0;
        }
 
-       os_snprintf(ifname, sizeof(ifname), "p2p-%s-%d", wpa_s->ifname,
-                   wpa_s->p2p_group_idx);
-       if (os_strlen(ifname) >= IFNAMSIZ &&
-           os_strlen(wpa_s->ifname) < IFNAMSIZ) {
-               /* Try to avoid going over the IFNAMSIZ length limit */
-               os_snprintf(ifname, sizeof(ifname), "p2p-%d",
-                           wpa_s->p2p_group_idx);
-       }
+       wpas_p2p_get_group_ifname(wpa_s, ifname, sizeof(ifname));
        force_ifname[0] = '\0';
 
        wpa_printf(MSG_DEBUG, "P2P: Create a new interface %s for the group",
@@ -1107,7 +1122,13 @@ wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go)
        os_memset(&iface, 0, sizeof(iface));
        iface.ifname = wpa_s->pending_interface_name;
        iface.driver = wpa_s->driver->name;
-       iface.ctrl_interface = wpa_s->conf->ctrl_interface;
+       if (wpa_s->conf->ctrl_interface == NULL &&
+           wpa_s->parent != wpa_s &&
+           wpa_s->p2p_mgmt &&
+           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE))
+               iface.ctrl_interface = wpa_s->parent->conf->ctrl_interface;
+       else
+               iface.ctrl_interface = wpa_s->conf->ctrl_interface;
        iface.driver_param = wpa_s->conf->driver_param;
        group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
        if (group_wpa_s == NULL) {
@@ -1132,6 +1153,14 @@ static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
        wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
+       wpas_p2p_group_formation_failed(wpa_s);
+}
+
+
+void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+{
+       eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+                            wpa_s->parent, NULL);
        if (wpa_s->global->p2p)
                p2p_group_formation_failed(wpa_s->global->p2p);
        else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
@@ -3048,6 +3077,45 @@ static void wpas_p2p_debug_print(void *ctx, int level, const char *msg)
 }
 
 
+int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_interface iface;
+       struct wpa_supplicant *p2pdev_wpa_s;
+       char ifname[100];
+       char force_name[100];
+       int ret;
+
+       os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
+                   wpa_s->ifname);
+       force_name[0] = '\0';
+       wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
+       ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
+                            force_name, wpa_s->pending_interface_addr, NULL);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to create P2P Device interface");
+               return ret;
+       }
+       os_strlcpy(wpa_s->pending_interface_name, ifname,
+                  sizeof(wpa_s->pending_interface_name));
+
+       os_memset(&iface, 0, sizeof(iface));
+       iface.p2p_mgmt = 1;
+       iface.ifname = wpa_s->pending_interface_name;
+       iface.driver = wpa_s->driver->name;
+       iface.driver_param = wpa_s->conf->driver_param;
+       iface.confname = wpa_s->confname;
+       p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+       if (!p2pdev_wpa_s) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface");
+               return -1;
+       }
+       p2pdev_wpa_s->parent = wpa_s;
+
+       wpa_s->pending_interface_name[0] = '\0';
+       return 0;
+}
+
+
 /**
  * wpas_p2p_init - Initialize P2P module for %wpa_supplicant
  * @global: Pointer to global data from wpa_supplicant_init()
@@ -3312,7 +3380,8 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
 
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
 {
-       if (wpa_s->conf->p2p_no_group_iface)
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+           wpa_s->conf->p2p_no_group_iface)
                return 0; /* separate interface disabled per configuration */
        if (wpa_s->drv_flags &
            (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
@@ -5595,14 +5664,7 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
                   "session overlap");
        if (wpa_s != wpa_s->parent)
                wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
-
-       if (wpa_s->global->p2p)
-               p2p_group_formation_failed(wpa_s->global->p2p);
-
-       eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
-                            wpa_s->parent, NULL);
-
-       wpas_group_formation_completed(wpa_s, 0);
+       wpas_p2p_group_formation_failed(wpa_s);
        return 1;
 }
 
index 04ba9b2..3ca6222 100644 (file)
@@ -14,10 +14,12 @@ struct p2p_go_neg_results;
 enum p2p_send_action_result;
 struct p2p_peer_info;
 struct p2p_channels;
+struct wps_event_fail;
 
 int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
 void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
 void wpas_p2p_deinit_global(struct wpa_global *global);
+int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s);
 int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                     const char *pin, enum p2p_wps_method wps_method,
                     int persistent_group, int auto_join, int join,
@@ -76,6 +78,7 @@ void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
 void wpas_dev_found(void *ctx, const u8 *addr,
                    const struct p2p_peer_info *info,
                    int new_device);
+void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s);
 void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res);
 void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id);
 void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
index 27791b3..f6b881b 100644 (file)
@@ -17,6 +17,7 @@
 #include "crypto/sha1.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eap_peer/eap.h"
+#include "eap_peer/eap_proxy.h"
 #include "eap_server/eap_methods.h"
 #include "rsn_supp/wpa.h"
 #include "eloop.h"
@@ -2348,7 +2349,10 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
                const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
                if (addr)
                        os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
-       } else if (!(wpa_s->drv_flags &
+       } else if ((!wpa_s->p2p_mgmt ||
+                   !(wpa_s->drv_flags &
+                     WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+                  !(wpa_s->drv_flags &
                     WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
                l2_packet_deinit(wpa_s->l2);
                wpa_s->l2 = l2_packet_init(wpa_s->ifname,
@@ -2368,10 +2372,6 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
                return -1;
        }
 
-       wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
-               MAC2STR(wpa_s->own_addr));
-       wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
-
        return 0;
 }
 
@@ -2417,6 +2417,10 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
        if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
                return -1;
 
+       wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
+               MAC2STR(wpa_s->own_addr));
+       wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
        if (wpa_s->bridge_ifname[0]) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
                        "interface '%s'", wpa_s->bridge_ifname);
@@ -2855,6 +2859,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                        wpa_s->conf->driver_param =
                                os_strdup(iface->driver_param);
                }
+
+               if (iface->p2p_mgmt && !iface->ctrl_interface) {
+                       os_free(wpa_s->conf->ctrl_interface);
+                       wpa_s->conf->ctrl_interface = NULL;
+               }
        } else
                wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
                                                     iface->driver_param);
@@ -2980,11 +2989,24 @@ next_driver:
        if (wpa_s->max_remain_on_chan == 0)
                wpa_s->max_remain_on_chan = 1000;
 
+       /*
+        * Only take p2p_mgmt parameters when P2P Device is supported.
+        * Doing it here as it determines whether l2_packet_init() will be done
+        * during wpa_supplicant_driver_init().
+        */
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
+               wpa_s->p2p_mgmt = iface->p2p_mgmt;
+       else
+               iface->p2p_mgmt = 1;
+
        if (wpa_supplicant_driver_init(wpa_s) < 0)
                return -1;
 
 #ifdef CONFIG_TDLS
-       if (wpa_tdls_init(wpa_s->wpa))
+       if ((!iface->p2p_mgmt ||
+            !(wpa_s->drv_flags &
+              WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+           wpa_tdls_init(wpa_s->wpa))
                return -1;
 #endif /* CONFIG_TDLS */
 
@@ -3022,7 +3044,7 @@ next_driver:
        }
 
 #ifdef CONFIG_P2P
-       if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+       if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
                wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
                return -1;
        }
@@ -3031,6 +3053,20 @@ next_driver:
        if (wpa_bss_init(wpa_s) < 0)
                return -1;
 
+#ifdef CONFIG_EAP_PROXY
+{
+       size_t len;
+       wpa_s->mnc_len = eap_proxy_get_imsi(wpa_s->imsi, &len);
+       if (wpa_s->mnc_len > 0) {
+               wpa_s->imsi[len] = '\0';
+               wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
+                          wpa_s->imsi, wpa_s->mnc_len);
+       } else {
+               wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+       }
+}
+#endif /* CONFIG_EAP_PROXY */
+
        if (pcsc_reader_init(wpa_s) < 0)
                return -1;
 
@@ -3422,9 +3458,6 @@ void wpa_supplicant_deinit(struct wpa_global *global)
 #ifdef CONFIG_WIFI_DISPLAY
        wifi_display_deinit(global);
 #endif /* CONFIG_WIFI_DISPLAY */
-#ifdef CONFIG_P2P
-       wpas_p2p_deinit_global(global);
-#endif /* CONFIG_P2P */
 
        while (global->ifaces)
                wpa_supplicant_remove_iface(global, global->ifaces, 1);
index 8e21a3a..d73d371 100644 (file)
@@ -815,6 +815,11 @@ fast_reauth=1
 #      interface used for EAPOL. The default value is suitable for most
 #      cases.
 #
+# ocsp: Whether to use/require OCSP to check server certificate
+#      0 = do not use OCSP stapling (TLS certificate status extension)
+#      1 = try to use OCSP stapling, but not require response
+#      2 = require valid OCSP stapling response
+#
 # EAP-FAST variables:
 # pac_file: File path for the PAC entries. wpa_supplicant will need to be able
 #      to create this file and write updates to it when PAC is being
index c971ae4..9240863 100644 (file)
@@ -104,6 +104,15 @@ struct wpa_interface {
         * receiving of EAPOL frames from an additional interface.
         */
        const char *bridge_ifname;
+
+       /**
+        * p2p_mgmt - Interface used for P2P management (P2P Device operations)
+        *
+        * Indicates whether wpas_p2p_init() must be called for this interface.
+        * This is used only when the driver supports a dedicated P2P Device
+        * interface that is not a network interface.
+        */
+       int p2p_mgmt;
 };
 
 /**
@@ -407,10 +416,8 @@ struct wpa_supplicant {
                             * previous association event */
 
        struct scard_data *scard;
-#ifdef PCSC_FUNCS
        char imsi[20];
        int mnc_len;
-#endif /* PCSC_FUNCS */
 
        unsigned char last_eapol_src[ETH_ALEN];
 
@@ -568,6 +575,8 @@ struct wpa_supplicant {
        unsigned int roc_waiting_drv_freq;
        int action_tx_wait_time;
 
+       int p2p_mgmt;
+
 #ifdef CONFIG_P2P
        struct p2p_go_neg_results *go_params;
        int create_p2p_iface;
index 40720c5..61a42bd 100644 (file)
@@ -513,8 +513,6 @@ static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
 }
 #endif /* CONFIG_IEEE80211R */
 
-#endif /* CONFIG_NO_WPA */
-
 
 #ifdef CONFIG_TDLS
 
@@ -596,6 +594,8 @@ static int wpa_supplicant_tdls_peer_addset(
 
 #endif /* CONFIG_TDLS */
 
+#endif /* CONFIG_NO_WPA */
+
 
 enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
 {
index d73e023..8e0207c 100644 (file)
@@ -868,9 +868,8 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
        while (ssid) {
                if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
                        if (ssid == wpa_s->current_ssid) {
-                               wpa_s->current_ssid = NULL;
-                               if (ssid != NULL)
-                                       wpas_notify_network_changed(wpa_s);
+                               wpa_supplicant_deauthenticate(
+                                       wpa_s, WLAN_REASON_DEAUTH_LEAVING);
                        }
                        id = ssid->id;
                        remove_ssid = ssid;