aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2012-01-24 16:10:04 -0800
committerDmitry Shmidt <dimitrysh@google.com>2012-01-24 16:44:49 -0800
commit1f69aa52ea2e0a73ac502565df8c666ee49cab6a (patch)
tree8ea94735f75f461769454853da0c24cbb89cc4cc /src
parentbf5edf439c90418b6f4122ff5e3925123263bda4 (diff)
downloadexternal_wpa_supplicant_8-1f69aa52ea2e0a73ac502565df8c666ee49cab6a.zip
external_wpa_supplicant_8-1f69aa52ea2e0a73ac502565df8c666ee49cab6a.tar.gz
external_wpa_supplicant_8-1f69aa52ea2e0a73ac502565df8c666ee49cab6a.tar.bz2
Update to new version 0.8.16 from BRCM
Sync with main tree commit b8349523e460493fa0b4de36c689595109e45e91 Author: Neeraj Kumar Garg <neerajkg@broadcom.com> Date: Tue Dec 27 23:21:45 2011 +0200 P2P: Reject p2p_group_add if forced frequency is not acceptable Change-Id: Icb4541a371b05c270e80440d7a7fdea7f33ff61e Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/ap/accounting.c4
-rw-r--r--src/ap/ap_config.c8
-rw-r--r--src/ap/ap_config.h48
-rw-r--r--src/ap/ap_drv_ops.c364
-rw-r--r--src/ap/ap_drv_ops.h52
-rw-r--r--src/ap/authsrv.c10
-rw-r--r--src/ap/beacon.c420
-rw-r--r--src/ap/beacon.h10
-rw-r--r--src/ap/drv_callbacks.c193
-rw-r--r--src/ap/hostapd.c34
-rw-r--r--src/ap/hostapd.h28
-rw-r--r--src/ap/hw_features.c72
-rw-r--r--src/ap/hw_features.h5
-rw-r--r--src/ap/ieee802_11.c380
-rw-r--r--src/ap/ieee802_11.h14
-rw-r--r--src/ap/ieee802_11_auth.c58
-rw-r--r--src/ap/ieee802_11_auth.h3
-rw-r--r--src/ap/ieee802_11_shared.c405
-rw-r--r--src/ap/ieee802_1x.c144
-rw-r--r--src/ap/ieee802_1x.h2
-rw-r--r--src/ap/sta_info.c194
-rw-r--r--src/ap/sta_info.h15
-rw-r--r--src/ap/tkip_countermeasures.c16
-rw-r--r--src/ap/tkip_countermeasures.h3
-rw-r--r--src/ap/utils.c1
-rw-r--r--src/ap/wmm.c19
-rw-r--r--src/ap/wpa_auth.c113
-rw-r--r--src/ap/wpa_auth.h1
-rw-r--r--src/ap/wpa_auth_ft.c162
-rw-r--r--src/ap/wpa_auth_glue.c10
-rw-r--r--src/ap/wpa_auth_i.h1
-rw-r--r--src/ap/wpa_auth_ie.c12
-rw-r--r--src/ap/wps_hostapd.c78
-rw-r--r--src/common/defs.h22
-rw-r--r--src/common/gas.c279
-rw-r--r--src/common/gas.h42
-rw-r--r--src/common/ieee802_11_common.c44
-rw-r--r--src/common/ieee802_11_common.h4
-rw-r--r--src/common/ieee802_11_defs.h161
-rw-r--r--src/common/version.h2
-rw-r--r--src/common/wpa_common.c148
-rw-r--r--src/common/wpa_common.h23
-rw-r--r--src/common/wpa_ctrl.c51
-rwxr-xr-x[-rw-r--r--]src/common/wpa_ctrl.h17
-rw-r--r--src/crypto/Makefile3
-rw-r--r--src/crypto/aes-internal-dec.c2
-rw-r--r--src/crypto/aes-internal-enc.c2
-rw-r--r--src/crypto/crypto.h3
-rw-r--r--src/crypto/crypto_internal-rsa.c1
-rw-r--r--src/crypto/crypto_internal.c84
-rw-r--r--src/crypto/dh_group5.c2
-rw-r--r--src/crypto/fips_prf_internal.c5
-rw-r--r--src/crypto/md5-internal.c2
-rw-r--r--src/crypto/ms_funcs.c106
-rw-r--r--src/crypto/random.c18
-rw-r--r--src/crypto/sha1-pbkdf2.c2
-rw-r--r--src/crypto/sha1-tlsprf.c7
-rw-r--r--src/crypto/sha1.h6
-rw-r--r--src/crypto/sha256-internal.c43
-rw-r--r--src/crypto/sha256-tlsprf.c72
-rw-r--r--src/crypto/sha256.h5
-rw-r--r--src/crypto/sha256_i.h31
-rw-r--r--src/crypto/tls.h69
-rw-r--r--src/crypto/tls_gnutls.c331
-rw-r--r--src/crypto/tls_internal.c72
-rw-r--r--src/crypto/tls_none.c29
-rw-r--r--src/crypto/tls_nss.c29
-rw-r--r--src/crypto/tls_openssl.c34
-rw-r--r--src/crypto/tls_schannel.c29
-rw-r--r--src/drivers/Apple80211.h156
-rw-r--r--src/drivers/MobileApple80211.c189
-rw-r--r--src/drivers/MobileApple80211.h43
-rw-r--r--src/drivers/android_drv.h62
-rw-r--r--src/drivers/driver.h691
-rw-r--r--src/drivers/driver_atheros.c56
-rw-r--r--src/drivers/driver_broadcom.c599
-rw-r--r--src/drivers/driver_common.c90
-rw-r--r--src/drivers/driver_hostap.c545
-rw-r--r--src/drivers/driver_iphone.m466
-rw-r--r--src/drivers/driver_madwifi.c581
-rw-r--r--src/drivers/driver_ndis.c146
-rw-r--r--src/drivers/driver_nl80211.c3893
-rw-r--r--src/drivers/driver_osx.m459
-rw-r--r--src/drivers/driver_ralink.c1498
-rw-r--r--src/drivers/driver_ralink.h383
-rw-r--r--src/drivers/driver_roboswitch.c2
-rw-r--r--src/drivers/driver_test.c105
-rw-r--r--src/drivers/driver_wext.c181
-rw-r--r--src/drivers/driver_wext.h8
-rw-r--r--src/drivers/drivers.c24
-rw-r--r--src/drivers/drivers.mak83
-rw-r--r--src/drivers/drivers.mk83
-rw-r--r--src/drivers/linux_ioctl.c29
-rw-r--r--src/drivers/linux_ioctl.h1
-rw-r--r--src/drivers/linux_wext.h51
-rw-r--r--src/drivers/netlink.c2
-rw-r--r--src/drivers/nl80211_copy.h885
-rw-r--r--src/drivers/wireless_copy.h1185
-rw-r--r--src/eap_common/eap_fast_common.c6
-rw-r--r--src/eap_common/eap_peap_common.c13
-rw-r--r--src/eap_common/eap_peap_common.h8
-rw-r--r--src/eap_common/eap_pwd_common.c28
-rw-r--r--src/eap_common/eap_pwd_common.h7
-rw-r--r--src/eap_common/ikev2_common.h2
-rw-r--r--src/eap_peer/eap.c48
-rw-r--r--src/eap_peer/eap.h9
-rw-r--r--src/eap_peer/eap_aka.c17
-rw-r--r--src/eap_peer/eap_fast.c17
-rw-r--r--src/eap_peer/eap_methods.c2
-rw-r--r--src/eap_peer/eap_peap.c21
-rw-r--r--src/eap_peer/eap_pwd.c52
-rw-r--r--src/eap_peer/eap_sim.c23
-rw-r--r--src/eap_peer/eap_tls_common.c7
-rw-r--r--src/eap_peer/eap_tls_common.h5
-rw-r--r--src/eap_peer/eap_tnc.c1
-rw-r--r--src/eap_peer/eap_ttls.c450
-rw-r--r--src/eap_peer/ikev2.c2
-rw-r--r--src/eap_server/eap.h2
-rw-r--r--src/eap_server/eap_i.h2
-rw-r--r--src/eap_server/eap_server.c17
-rw-r--r--src/eap_server/eap_server_aka.c3
-rw-r--r--src/eap_server/eap_server_methods.c2
-rw-r--r--src/eap_server/eap_server_mschapv2.c9
-rw-r--r--src/eap_server/eap_server_peap.c17
-rw-r--r--src/eap_server/eap_server_psk.c4
-rw-r--r--src/eap_server/eap_server_pwd.c57
-rw-r--r--src/eap_server/eap_server_tls_common.c6
-rw-r--r--src/eap_server/eap_server_ttls.c269
-rw-r--r--src/eap_server/ikev2.c2
-rw-r--r--src/eapol_auth/eapol_auth_sm.c2
-rw-r--r--src/eapol_supp/eapol_supp_sm.c5
-rw-r--r--src/eapol_supp/eapol_supp_sm.h9
-rwxr-xr-x[-rw-r--r--]src/p2p/p2p.c347
-rwxr-xr-x[-rw-r--r--]src/p2p/p2p.h142
-rw-r--r--src/p2p/p2p_build.c15
-rw-r--r--src/p2p/p2p_go_neg.c69
-rw-r--r--src/p2p/p2p_group.c88
-rw-r--r--src/p2p/p2p_i.h31
-rw-r--r--src/p2p/p2p_invitation.c4
-rw-r--r--src/p2p/p2p_pd.c60
-rw-r--r--src/p2p/p2p_sd.c156
-rw-r--r--src/radius/radius.c121
-rw-r--r--src/radius/radius.h4
-rw-r--r--src/radius/radius_server.c32
-rw-r--r--src/radius/radius_server.h6
-rw-r--r--src/rsn_supp/pmksa_cache.c60
-rw-r--r--src/rsn_supp/pmksa_cache.h11
-rw-r--r--src/rsn_supp/preauth.c1
-rw-r--r--src/rsn_supp/tdls.c375
-rw-r--r--src/rsn_supp/wpa.c31
-rw-r--r--src/rsn_supp/wpa.h28
-rw-r--r--src/rsn_supp/wpa_ft.c179
-rw-r--r--src/rsn_supp/wpa_i.h39
-rw-r--r--src/rsn_supp/wpa_ie.c12
-rw-r--r--src/rsn_supp/wpa_ie.h4
-rw-r--r--src/tls/Makefile2
-rw-r--r--src/tls/libtommath.c14
-rw-r--r--src/tls/pkcs5.c2
-rw-r--r--src/tls/tlsv1_client.c235
-rw-r--r--src/tls/tlsv1_client.h10
-rw-r--r--src/tls/tlsv1_client_i.h2
-rw-r--r--src/tls/tlsv1_client_read.c38
-rw-r--r--src/tls/tlsv1_client_write.c144
-rw-r--r--src/tls/tlsv1_common.c91
-rw-r--r--src/tls/tlsv1_common.h57
-rw-r--r--src/tls/tlsv1_cred.c25
-rw-r--r--src/tls/tlsv1_record.c220
-rw-r--r--src/tls/tlsv1_record.h9
-rw-r--r--src/tls/tlsv1_server.c88
-rw-r--r--src/tls/tlsv1_server.h4
-rw-r--r--src/tls/tlsv1_server_read.c145
-rw-r--r--src/tls/tlsv1_server_write.c108
-rw-r--r--src/utils/base64.c27
-rw-r--r--src/utils/edit.c29
-rw-r--r--src/utils/eloop.h2
-rw-r--r--src/utils/includes.h1
-rw-r--r--src/utils/list.h3
-rw-r--r--src/utils/os.h10
-rw-r--r--src/utils/os_internal.c18
-rw-r--r--src/utils/os_none.c5
-rw-r--r--src/utils/os_unix.c22
-rw-r--r--src/utils/os_win32.c19
-rw-r--r--src/utils/pcsc_funcs.c2
-rw-r--r--src/utils/radiotap.h1
-rw-r--r--src/utils/wpa_debug.c2
-rw-r--r--src/utils/wpa_debug.h2
-rw-r--r--src/wps/upnp_xml.c4
-rw-r--r--src/wps/upnp_xml.h2
-rw-r--r--src/wps/wps.c45
-rw-r--r--src/wps/wps.h6
-rw-r--r--src/wps/wps_attr_parse.c4
-rw-r--r--src/wps/wps_common.c1
-rw-r--r--src/wps/wps_enrollee.c8
-rw-r--r--src/wps/wps_er.c47
-rw-r--r--src/wps/wps_registrar.c105
-rw-r--r--src/wps/wps_ufd.c1
-rw-r--r--src/wps/wps_upnp.c4
-rw-r--r--src/wps/wps_upnp_ssdp.c12
-rw-r--r--src/wps/wps_upnp_web.c2
199 files changed, 10662 insertions, 11010 deletions
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index dbfb058..03421b3 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -236,6 +236,7 @@ static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
{
struct radius_msg *msg;
+ struct os_time t;
int interval;
if (sta->acct_session_started)
@@ -247,7 +248,8 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
"starting accounting session %08X-%08X",
sta->acct_session_id_hi, sta->acct_session_id_lo);
- time(&sta->acct_session_start);
+ os_get_time(&t);
+ sta->acct_session_start = t.sec;
sta->last_rx_bytes = sta->last_tx_bytes = 0;
sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
hostapd_drv_sta_clear_stats(hapd, sta->addr);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index e77716b..b24cd90 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -426,6 +426,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
ssid->dyn_vlan_keys = NULL;
}
+ os_free(conf->time_zone);
+
#ifdef CONFIG_IEEE80211R
{
struct ft_remote_r0kh *r0kh, *r0kh_prev;
@@ -467,6 +469,12 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->model_url);
os_free(conf->upc);
#endif /* CONFIG_WPS */
+
+ os_free(conf->roaming_consortium);
+
+#ifdef CONFIG_RADIUS_TEST
+ os_free(conf->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 09eed5a..485092d 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -104,7 +104,6 @@ struct hostapd_wpa_psk {
u8 addr[ETH_ALEN];
};
-#define EAP_USER_MAX_METHODS 8
struct hostapd_eap_user {
struct hostapd_eap_user *next;
u8 *identity;
@@ -112,7 +111,7 @@ struct hostapd_eap_user {
struct {
int vendor;
u32 method;
- } methods[EAP_USER_MAX_METHODS];
+ } methods[EAP_MAX_METHODS];
u8 *password;
size_t password_len;
int phase2;
@@ -142,6 +141,13 @@ struct hostapd_wmm_ac_params {
};
+#define MAX_ROAMING_CONSORTIUM_LEN 15
+
+struct hostapd_roaming_consortium {
+ u8 len;
+ u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+};
+
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
@@ -213,6 +219,11 @@ struct hostapd_bss_config {
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
#endif /* CONFIG_IEEE80211W */
+ enum {
+ PSK_RADIUS_IGNORED = 0,
+ PSK_RADIUS_ACCEPTED = 1,
+ PSK_RADIUS_REQUIRED = 2
+ } wpa_psk_radius;
int wpa_pairwise;
int wpa_group;
int wpa_group_rekey;
@@ -329,11 +340,38 @@ struct hostapd_bss_config {
int p2p;
int disassoc_low_ack;
+ int skip_inactivity_poll;
#define TDLS_PROHIBIT BIT(0)
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
int tdls;
int disable_11n;
+
+ /* IEEE 802.11v */
+ int time_advertisement;
+ char *time_zone;
+
+ /* IEEE 802.11u - Interworking */
+ int interworking;
+ int access_network_type;
+ int internet;
+ int asra;
+ int esr;
+ int uesa;
+ int venue_info_set;
+ u8 venue_group;
+ u8 venue_type;
+ u8 hessid[ETH_ALEN];
+
+ /* IEEE 802.11u - Roaming Consortium list */
+ unsigned int roaming_consortium_count;
+ struct hostapd_roaming_consortium *roaming_consortium;
+
+ u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
+
+#ifdef CONFIG_RADIUS_TEST
+ char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
};
@@ -354,12 +392,6 @@ struct hostapd_config {
LONG_PREAMBLE = 0,
SHORT_PREAMBLE = 1
} preamble;
- enum {
- CTS_PROTECTION_AUTOMATIC = 0,
- CTS_PROTECTION_FORCE_ENABLED = 1,
- CTS_PROTECTION_FORCE_DISABLED = 2,
- CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
- } cts_protection_type;
int *supported_rates;
int *basic_rates;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 0b6836c..429c187 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -41,117 +41,159 @@ u32 hostapd_sta_flags_to_drv(u32 flags)
}
-int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+ struct wpabuf **beacon_ret,
+ struct wpabuf **proberesp_ret,
+ struct wpabuf **assocresp_ret)
{
- struct wpabuf *beacon, *proberesp, *assocresp = NULL;
- int ret;
+ struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL;
+ u8 buf[200], *pos;
- if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
- return 0;
+ *beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
+
+ pos = buf;
+ pos = hostapd_eid_time_adv(hapd, pos);
+ if (pos != buf) {
+ if (wpabuf_resize(&beacon, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(beacon, buf, pos - buf);
+ }
+ pos = hostapd_eid_time_zone(hapd, pos);
+ if (pos != buf) {
+ if (wpabuf_resize(&proberesp, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(proberesp, buf, pos - buf);
+ }
+
+ pos = buf;
+ pos = hostapd_eid_ext_capab(hapd, pos);
+ if (pos != buf) {
+ if (wpabuf_resize(&assocresp, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(assocresp, buf, pos - buf);
+ }
+ pos = hostapd_eid_interworking(hapd, pos);
+ pos = hostapd_eid_adv_proto(hapd, pos);
+ pos = hostapd_eid_roaming_consortium(hapd, pos);
+ if (pos != buf) {
+ if (wpabuf_resize(&beacon, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(beacon, buf, pos - buf);
+
+ if (wpabuf_resize(&proberesp, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(proberesp, buf, pos - buf);
+ }
+
+ if (hapd->wps_beacon_ie) {
+ if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
+ 0)
+ goto fail;
+ wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
+ }
- beacon = hapd->wps_beacon_ie;
- proberesp = hapd->wps_probe_resp_ie;
+ if (hapd->wps_probe_resp_ie) {
+ if (wpabuf_resize(&proberesp,
+ wpabuf_len(hapd->wps_probe_resp_ie)) < 0)
+ goto fail;
+ wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
+ }
#ifdef CONFIG_P2P
- if (hapd->wps_beacon_ie == NULL && hapd->p2p_beacon_ie == NULL)
- beacon = NULL;
- else {
- beacon = wpabuf_alloc((hapd->wps_beacon_ie ?
- wpabuf_len(hapd->wps_beacon_ie) : 0) +
- (hapd->p2p_beacon_ie ?
- wpabuf_len(hapd->p2p_beacon_ie) : 0));
- if (beacon == NULL)
- return -1;
- if (hapd->wps_beacon_ie)
- wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
- if (hapd->p2p_beacon_ie)
- wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
+ if (hapd->p2p_beacon_ie) {
+ if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) <
+ 0)
+ goto fail;
+ wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
}
- if (hapd->wps_probe_resp_ie == NULL && hapd->p2p_probe_resp_ie == NULL)
- proberesp = NULL;
- else {
- proberesp = wpabuf_alloc(
- (hapd->wps_probe_resp_ie ?
- wpabuf_len(hapd->wps_probe_resp_ie) : 0) +
- (hapd->p2p_probe_resp_ie ?
- wpabuf_len(hapd->p2p_probe_resp_ie) : 0));
- if (proberesp == NULL) {
- wpabuf_free(beacon);
- return -1;
- }
- if (hapd->wps_probe_resp_ie)
- wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
- if (hapd->p2p_probe_resp_ie)
- wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
+ if (hapd->p2p_probe_resp_ie) {
+ if (wpabuf_resize(&proberesp,
+ wpabuf_len(hapd->p2p_probe_resp_ie)) < 0)
+ goto fail;
+ wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
}
#endif /* CONFIG_P2P */
#ifdef CONFIG_P2P_MANAGER
if (hapd->conf->p2p & P2P_MANAGE) {
- struct wpabuf *a;
-
- a = wpabuf_alloc(100 + (beacon ? wpabuf_len(beacon) : 0));
- if (a) {
+ if (wpabuf_resize(&beacon, 100) == 0) {
u8 *start, *p;
- if (beacon)
- wpabuf_put_buf(a, beacon);
- if (beacon != hapd->wps_beacon_ie)
- wpabuf_free(beacon);
- start = wpabuf_put(a, 0);
+ start = wpabuf_put(beacon, 0);
p = hostapd_eid_p2p_manage(hapd, start);
- wpabuf_put(a, p - start);
- beacon = a;
+ wpabuf_put(beacon, p - start);
}
- a = wpabuf_alloc(100 + (proberesp ? wpabuf_len(proberesp) :
- 0));
- if (a) {
+ if (wpabuf_resize(&proberesp, 100) == 0) {
u8 *start, *p;
- if (proberesp)
- wpabuf_put_buf(a, proberesp);
- if (proberesp != hapd->wps_probe_resp_ie)
- wpabuf_free(proberesp);
- start = wpabuf_put(a, 0);
+ start = wpabuf_put(proberesp, 0);
p = hostapd_eid_p2p_manage(hapd, start);
- wpabuf_put(a, p - start);
- proberesp = a;
+ wpabuf_put(proberesp, p - start);
}
}
#endif /* CONFIG_P2P_MANAGER */
#ifdef CONFIG_WPS2
- if (hapd->conf->wps_state)
- assocresp = wps_build_assoc_resp_ie();
+ if (hapd->conf->wps_state) {
+ struct wpabuf *a = wps_build_assoc_resp_ie();
+ if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
+ wpabuf_put_buf(assocresp, a);
+ wpabuf_free(a);
+ }
#endif /* CONFIG_WPS2 */
#ifdef CONFIG_P2P_MANAGER
if (hapd->conf->p2p & P2P_MANAGE) {
- struct wpabuf *a;
- a = wpabuf_alloc(100 + (assocresp ? wpabuf_len(assocresp) :
- 0));
- if (a) {
+ if (wpabuf_resize(&assocresp, 100) == 0) {
u8 *start, *p;
- start = wpabuf_put(a, 0);
+ start = wpabuf_put(assocresp, 0);
p = hostapd_eid_p2p_manage(hapd, start);
- wpabuf_put(a, p - start);
- if (assocresp) {
- wpabuf_put_buf(a, assocresp);
- wpabuf_free(assocresp);
- }
- assocresp = a;
+ wpabuf_put(assocresp, p - start);
}
}
#endif /* CONFIG_P2P_MANAGER */
+ *beacon_ret = beacon;
+ *proberesp_ret = proberesp;
+ *assocresp_ret = assocresp;
+
+ return 0;
+
+fail:
+ wpabuf_free(beacon);
+ wpabuf_free(proberesp);
+ wpabuf_free(assocresp);
+ return -1;
+}
+
+
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd,
+ struct wpabuf *beacon,
+ struct wpabuf *proberesp,
+ struct wpabuf *assocresp)
+{
+ wpabuf_free(beacon);
+ wpabuf_free(proberesp);
+ wpabuf_free(assocresp);
+}
+
+
+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
+{
+ struct wpabuf *beacon, *proberesp, *assocresp;
+ int ret;
+
+ if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
+ return 0;
+
+ if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
+ 0)
+ return -1;
+
ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
assocresp);
- if (beacon != hapd->wps_beacon_ie)
- wpabuf_free(beacon);
- if (proberesp != hapd->wps_probe_resp_ie)
- wpabuf_free(proberesp);
- wpabuf_free(assocresp);
+ hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
return ret;
}
@@ -211,74 +253,6 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
}
-static int hostapd_set_ap_isolate(struct hostapd_data *hapd, int value)
-{
- if (hapd->driver == NULL || hapd->driver->set_intra_bss == NULL)
- return 0;
- return hapd->driver->set_intra_bss(hapd->drv_priv, !value);
-}
-
-
-int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection)
-{
- int ret = 0;
- int preamble;
-#ifdef CONFIG_IEEE80211N
- u8 buf[60], *ht_capab, *ht_oper, *pos;
-
- pos = buf;
- ht_capab = pos;
- pos = hostapd_eid_ht_capabilities(hapd, pos);
- ht_oper = pos;
- pos = hostapd_eid_ht_operation(hapd, pos);
- if (pos > ht_oper && ht_oper > ht_capab &&
- hostapd_set_ht_params(hapd, ht_capab + 2, ht_capab[1],
- ht_oper + 2, ht_oper[1])) {
- wpa_printf(MSG_ERROR, "Could not set HT capabilities "
- "for kernel driver");
- ret = -1;
- }
-
-#endif /* CONFIG_IEEE80211N */
-
- if (hostapd_set_cts_protect(hapd, use_protection)) {
- wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
- "driver");
- ret = -1;
- }
-
- if (hapd->iface->current_mode &&
- hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
- hostapd_set_short_slot_time(hapd,
- hapd->iface->num_sta_no_short_slot_time
- > 0 ? 0 : 1)) {
- wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option "
- "in kernel driver");
- ret = -1;
- }
-
- if (hapd->iface->num_sta_no_short_preamble == 0 &&
- hapd->iconf->preamble == SHORT_PREAMBLE)
- preamble = SHORT_PREAMBLE;
- else
- preamble = LONG_PREAMBLE;
- if (hostapd_set_preamble(hapd, preamble)) {
- wpa_printf(MSG_ERROR, "Could not set preamble for kernel "
- "driver");
- ret = -1;
- }
-
- if (hostapd_set_ap_isolate(hapd, hapd->conf->isolate) &&
- hapd->conf->isolate) {
- wpa_printf(MSG_ERROR, "Could not enable AP isolation in "
- "kernel driver");
- ret = -1;
- }
-
- return ret;
-}
-
-
int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
{
char force_ifname[IFNAMSIZ];
@@ -310,11 +284,41 @@ int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
}
+int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+ u16 auth_alg)
+{
+ if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
+ return 0;
+ return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
+}
+
+
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+ u16 seq, u16 status, const u8 *ie, size_t len)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
+ return 0;
+ return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr,
+ seq, status, ie, len);
+}
+
+
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+ int reassoc, u16 status, const u8 *ie, size_t len)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_assoc == NULL)
+ return 0;
+ return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr,
+ reassoc, status, ie, len);
+}
+
+
int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *addr, u16 aid, u16 capability,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
- const struct ieee80211_ht_capabilities *ht_capab)
+ const struct ieee80211_ht_capabilities *ht_capab,
+ u32 flags, u8 qosinfo)
{
struct hostapd_sta_add_params params;
@@ -331,10 +335,22 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.supp_rates_len = supp_rates_len;
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
+ params.flags = hostapd_sta_flags_to_drv(flags);
+ params.qosinfo = qosinfo;
return hapd->driver->sta_add(hapd->drv_priv, &params);
}
+int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
+ u8 *tspec_ie, size_t tspec_ielen)
+{
+ if (hapd->driver == NULL || hapd->driver->add_tspec == NULL)
+ return 0;
+ return hapd->driver->add_tspec(hapd->drv_priv, addr, tspec_ie,
+ tspec_ielen);
+}
+
+
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
{
if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
@@ -460,16 +476,6 @@ int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
}
-int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
- int *basic_rates, int mode)
-{
- if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
- return 0;
- return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates,
- basic_rates, mode);
-}
-
-
int hostapd_set_country(struct hostapd_data *hapd, const char *country)
{
if (hapd->driver == NULL ||
@@ -479,30 +485,6 @@ int hostapd_set_country(struct hostapd_data *hapd, const char *country)
}
-int hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
-{
- if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
- return 0;
- return hapd->driver->set_cts_protect(hapd->drv_priv, value);
-}
-
-
-int hostapd_set_preamble(struct hostapd_data *hapd, int value)
-{
- if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
- return 0;
- return hapd->driver->set_preamble(hapd->drv_priv, value);
-}
-
-
-int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
-{
- if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
- return 0;
- return hapd->driver->set_short_slot_time(hapd->drv_priv, value);
-}
-
-
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time)
{
@@ -513,15 +495,6 @@ int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
}
-int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
- const u8 *mask)
-{
- if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
- return 1;
- return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask);
-}
-
-
struct hostapd_hw_modes *
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
u16 *flags)
@@ -542,19 +515,6 @@ int hostapd_driver_commit(struct hostapd_data *hapd)
}
-int hostapd_set_ht_params(struct hostapd_data *hapd,
- const u8 *ht_capab, size_t ht_capab_len,
- const u8 *ht_oper, size_t ht_oper_len)
-{
- if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL ||
- ht_capab == NULL || ht_oper == NULL)
- return 0;
- return hapd->driver->set_ht_params(hapd->drv_priv,
- ht_capab, ht_capab_len,
- ht_oper, ht_oper_len);
-}
-
-
int hostapd_drv_none(struct hostapd_data *hapd)
{
return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
@@ -604,11 +564,11 @@ int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
- const void *msg, size_t len)
+ const void *msg, size_t len, int noack)
{
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0;
- return hapd->driver->send_mlme(hapd->drv_priv, msg, len);
+ return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index f6076af..835cdde 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -21,13 +21,19 @@ struct wpa_driver_scan_params;
struct ieee80211_ht_capabilities;
u32 hostapd_sta_flags_to_drv(u32 flags);
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+ struct wpabuf **beacon,
+ struct wpabuf **proberesp,
+ struct wpabuf **assocresp);
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
+ struct wpabuf *proberesp,
+ struct wpabuf *assocresp);
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
int enabled);
-int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection);
int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
@@ -36,7 +42,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *addr, u16 aid, u16 capability,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
- const struct ieee80211_ht_capabilities *ht_capab);
+ const struct ieee80211_ht_capabilities *ht_capab,
+ u32 flags, u8 qosinfo);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len);
@@ -59,23 +66,13 @@ int hostapd_set_rts(struct hostapd_data *hapd, int rts);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
int total_flags, int flags_or, int flags_and);
-int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
- int *basic_rates, int mode);
int hostapd_set_country(struct hostapd_data *hapd, const char *country);
-int hostapd_set_cts_protect(struct hostapd_data *hapd, int value);
-int hostapd_set_preamble(struct hostapd_data *hapd, int value);
-int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value);
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time);
-int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
- const u8 *mask);
struct hostapd_hw_modes *
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
u16 *flags);
int hostapd_driver_commit(struct hostapd_data *hapd);
-int hostapd_set_ht_params(struct hostapd_data *hapd,
- const u8 *ht_capab, size_t ht_capab_len,
- const u8 *ht_oper, size_t ht_oper_len);
int hostapd_drv_none(struct hostapd_data *hapd);
int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_driver_scan_params *params);
@@ -90,11 +87,19 @@ int hostapd_drv_set_key(const char *ifname,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len);
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
- const void *msg, size_t len);
+ const void *msg, size_t len, int noack);
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
const u8 *addr, int reason);
+int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+ u16 auth_alg);
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+ u16 seq, u16 status, const u8 *ie, size_t len);
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+ int reassoc, u16 status, const u8 *ie, size_t len);
+int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
+ u8 *tspec_ie, size_t tspec_ielen);
#include "drivers/driver.h"
@@ -163,16 +168,12 @@ static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd,
return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
}
-static inline int hostapd_drv_set_beacon(struct hostapd_data *hapd,
- const u8 *head, size_t head_len,
- const u8 *tail, size_t tail_len,
- int dtim_period, int beacon_int)
+static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params)
{
- if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
+ if (hapd->driver == NULL || hapd->driver->set_ap == NULL)
return 0;
- return hapd->driver->set_beacon(hapd->drv_priv,
- head, head_len, tail, tail_len,
- dtim_period, beacon_int);
+ return hapd->driver->set_ap(hapd->drv_priv, params);
}
static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd,
@@ -202,4 +203,13 @@ static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd,
return hapd->driver->set_authmode(hapd->drv_priv, auth_algs);
}
+static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
+ const u8 *own_addr, const u8 *addr,
+ int qos)
+{
+ if (hapd->driver == NULL || hapd->driver->poll_client == NULL)
+ return;
+ hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 7c87fde..6f56c95 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -60,7 +60,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
struct eap_user *user)
{
const struct hostapd_eap_user *eap_user;
- int i, count;
+ int i;
eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
if (eap_user == NULL)
@@ -70,10 +70,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
return 0;
os_memset(user, 0, sizeof(*user));
- count = EAP_USER_MAX_METHODS;
- if (count > EAP_MAX_METHODS)
- count = EAP_MAX_METHODS;
- for (i = 0; i < count; i++) {
+ for (i = 0; i < EAP_MAX_METHODS; i++) {
user->methods[i].vendor = eap_user->methods[i].vendor;
user->methods[i].method = eap_user->methods[i].method;
}
@@ -120,6 +117,9 @@ 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;
+#ifdef CONFIG_RADIUS_TEST
+ srv.dump_msk_file = conf->dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 0091064..4d8b277 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -35,6 +35,8 @@
#include "beacon.h"
+#ifdef NEED_AP_MLME
+
static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
{
u8 erp = 0;
@@ -43,23 +45,11 @@ static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return 0;
- switch (hapd->iconf->cts_protection_type) {
- case CTS_PROTECTION_FORCE_ENABLED:
- erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
- break;
- case CTS_PROTECTION_FORCE_DISABLED:
- erp = 0;
- break;
- case CTS_PROTECTION_AUTOMATIC:
- if (hapd->iface->olbc)
- erp |= ERP_INFO_USE_PROTECTION;
- /* continue */
- case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
- if (hapd->iface->num_sta_non_erp > 0) {
- erp |= ERP_INFO_NON_ERP_PRESENT |
- ERP_INFO_USE_PROTECTION;
- }
- break;
+ if (hapd->iface->olbc)
+ erp |= ERP_INFO_USE_PROTECTION;
+ if (hapd->iface->num_sta_non_erp > 0) {
+ erp |= ERP_INFO_NON_ERP_PRESENT |
+ ERP_INFO_USE_PROTECTION;
}
if (hapd->iface->num_sta_no_short_preamble > 0 ||
hapd->iconf->preamble == LONG_PREAMBLE)
@@ -182,8 +172,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
}
-static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
- struct sta_info *sta)
+static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
{
const u8 *ie;
size_t ielen;
@@ -197,30 +186,134 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
}
+static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const struct ieee80211_mgmt *req,
+ int is_p2p, size_t *resp_len)
+{
+ struct ieee80211_mgmt *resp;
+ u8 *pos, *epos;
+ size_t buflen;
+
+#define MAX_PROBERESP_LEN 768
+ buflen = MAX_PROBERESP_LEN;
+#ifdef CONFIG_WPS
+ if (hapd->wps_probe_resp_ie)
+ buflen += wpabuf_len(hapd->wps_probe_resp_ie);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ if (hapd->p2p_probe_resp_ie)
+ buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
+#endif /* CONFIG_P2P */
+ resp = os_zalloc(buflen);
+ if (resp == NULL)
+ return NULL;
+
+ epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
+
+ resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_PROBE_RESP);
+ if (req)
+ os_memcpy(resp->da, req->sa, ETH_ALEN);
+ os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+
+ os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+ resp->u.probe_resp.beacon_int =
+ host_to_le16(hapd->iconf->beacon_int);
+
+ /* hardware or low-level driver will setup seq_ctrl and timestamp */
+ resp->u.probe_resp.capab_info =
+ host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
+
+ pos = resp->u.probe_resp.variable;
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = hapd->conf->ssid.ssid_len;
+ os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len);
+ pos += hapd->conf->ssid.ssid_len;
+
+ /* Supported rates */
+ pos = hostapd_eid_supp_rates(hapd, pos);
+
+ /* DS Params */
+ pos = hostapd_eid_ds_params(hapd, pos);
+
+ pos = hostapd_eid_country(hapd, pos, epos - pos);
+
+ /* ERP Information element */
+ pos = hostapd_eid_erp_info(hapd, pos);
+
+ /* Extended supported rates */
+ pos = hostapd_eid_ext_supp_rates(hapd, pos);
+
+ /* RSN, MDIE, WPA */
+ pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+
+#ifdef CONFIG_IEEE80211N
+ pos = hostapd_eid_ht_capabilities(hapd, pos);
+ pos = hostapd_eid_ht_operation(hapd, pos);
+#endif /* CONFIG_IEEE80211N */
+
+ pos = hostapd_eid_ext_capab(hapd, pos);
+
+ pos = hostapd_eid_time_adv(hapd, pos);
+ pos = hostapd_eid_time_zone(hapd, pos);
+
+ pos = hostapd_eid_interworking(hapd, pos);
+ pos = hostapd_eid_adv_proto(hapd, pos);
+ pos = hostapd_eid_roaming_consortium(hapd, pos);
+
+ /* Wi-Fi Alliance WMM */
+ pos = hostapd_eid_wmm(hapd, pos);
+
+#ifdef CONFIG_WPS
+ if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
+ os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
+ wpabuf_len(hapd->wps_probe_resp_ie));
+ pos += wpabuf_len(hapd->wps_probe_resp_ie);
+ }
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+ if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p &&
+ hapd->p2p_probe_resp_ie) {
+ os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
+ wpabuf_len(hapd->p2p_probe_resp_ie));
+ pos += wpabuf_len(hapd->p2p_probe_resp_ie);
+ }
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_P2P_MANAGER
+ if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
+ P2P_MANAGE)
+ pos = hostapd_eid_p2p_manage(hapd, pos);
+#endif /* CONFIG_P2P_MANAGER */
+
+ *resp_len = pos - (u8 *) resp;
+ return (u8 *) resp;
+}
+
+
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
- struct ieee80211_mgmt *resp;
+ u8 *resp;
struct ieee802_11_elems elems;
- char *ssid;
- u8 *pos, *epos;
const u8 *ie;
- size_t ssid_len, ie_len;
+ size_t ie_len;
struct sta_info *sta = NULL;
- size_t buflen;
- size_t i;
+ size_t i, resp_len;
+ int noack;
ie = mgmt->u.probe_req.variable;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
return;
ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
-#ifndef ANDROID_BRCM_P2P_PATCH
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
- mgmt->sa, ie, ie_len) > 0)
+ mgmt->sa, mgmt->da, mgmt->bssid,
+ ie, ie_len) > 0)
return;
-#endif
+
if (!hapd->iconf->send_probe_response)
return;
@@ -230,9 +323,6 @@ void handle_probe_req(struct hostapd_data *hapd,
return;
}
- ssid = NULL;
- ssid_len = 0;
-
if ((!elems.ssid || !elems.supp_rates)) {
wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
"without SSID or supported rates element",
@@ -277,13 +367,9 @@ void handle_probe_req(struct hostapd_data *hapd,
(elems.ssid_len == hapd->conf->ssid.ssid_len &&
os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
0)) {
- ssid = hapd->conf->ssid.ssid;
- ssid_len = hapd->conf->ssid.ssid_len;
if (sta)
sta->ssid_probe = &hapd->conf->ssid;
- }
-
- if (!ssid) {
+ } else {
if (!(mgmt->da[0] & 0x01)) {
char ssid_txt[33];
ieee802_11_print_ssid(ssid_txt, elems.ssid,
@@ -296,113 +382,116 @@ void handle_probe_req(struct hostapd_data *hapd,
return;
}
+#ifdef CONFIG_INTERWORKING
+ if (elems.interworking && elems.interworking_len >= 1) {
+ u8 ant = elems.interworking[0] & 0x0f;
+ if (ant != INTERWORKING_ANT_WILDCARD &&
+ ant != hapd->conf->access_network_type) {
+ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+ " for mismatching ANT %u ignored",
+ MAC2STR(mgmt->sa), ant);
+ return;
+ }
+ }
+
+ if (elems.interworking &&
+ (elems.interworking_len == 7 || elems.interworking_len == 9)) {
+ const u8 *hessid;
+ if (elems.interworking_len == 7)
+ hessid = elems.interworking + 1;
+ else
+ hessid = elems.interworking + 1 + 2;
+ if (!is_broadcast_ether_addr(hessid) &&
+ os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+ " for mismatching HESSID " MACSTR
+ " ignored",
+ MAC2STR(mgmt->sa), MAC2STR(hessid));
+ return;
+ }
+ }
+#endif /* CONFIG_INTERWORKING */
+
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
-#define MAX_PROBERESP_LEN 768
- buflen = MAX_PROBERESP_LEN;
-#ifdef CONFIG_WPS
- if (hapd->wps_probe_resp_ie)
- buflen += wpabuf_len(hapd->wps_probe_resp_ie);
-#endif /* CONFIG_WPS */
-#ifdef CONFIG_P2P
- if (hapd->p2p_probe_resp_ie)
- buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
-#endif /* CONFIG_P2P */
- resp = os_zalloc(buflen);
+
+ resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
+ &resp_len);
if (resp == NULL)
return;
- epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
- resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_PROBE_RESP);
- os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
- os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+ /*
+ * If this is a broadcast probe request, apply no ack policy to avoid
+ * excessive retries.
+ */
+ noack = !!(elems.ssid_len == 0 && is_broadcast_ether_addr(mgmt->da));
- os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
- resp->u.probe_resp.beacon_int =
- host_to_le16(hapd->iconf->beacon_int);
-
- /* hardware or low-level driver will setup seq_ctrl and timestamp */
- resp->u.probe_resp.capab_info =
- host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
-
- pos = resp->u.probe_resp.variable;
- *pos++ = WLAN_EID_SSID;
- *pos++ = ssid_len;
- os_memcpy(pos, ssid, ssid_len);
- pos += ssid_len;
-
- /* Supported rates */
- pos = hostapd_eid_supp_rates(hapd, pos);
-
- /* DS Params */
- pos = hostapd_eid_ds_params(hapd, pos);
-
- pos = hostapd_eid_country(hapd, pos, epos - pos);
-
- /* ERP Information element */
- pos = hostapd_eid_erp_info(hapd, pos);
-
- /* Extended supported rates */
- pos = hostapd_eid_ext_supp_rates(hapd, pos);
+ if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
+ perror("handle_probe_req: send");
- /* RSN, MDIE, WPA */
- pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
+ os_free(resp);
-#ifdef CONFIG_IEEE80211N
- pos = hostapd_eid_ht_capabilities(hapd, pos);
- pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
+ wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s "
+ "SSID", MAC2STR(mgmt->sa),
+ elems.ssid_len == 0 ? "broadcast" : "our");
+}
- pos = hostapd_eid_ext_capab(hapd, pos);
- /* Wi-Fi Alliance WMM */
- pos = hostapd_eid_wmm(hapd, pos);
+static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
+ size_t *resp_len)
+{
+ /* check probe response offloading caps and print warnings */
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD))
+ return NULL;
#ifdef CONFIG_WPS
- if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
- os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
- wpabuf_len(hapd->wps_probe_resp_ie));
- pos += wpabuf_len(hapd->wps_probe_resp_ie);
- }
+ if (hapd->conf->wps_state && hapd->wps_probe_resp_ie &&
+ (!(hapd->iface->probe_resp_offloads &
+ (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS |
+ WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2))))
+ wpa_printf(MSG_WARNING, "Device is trying to offload WPS "
+ "Probe Response while not supporting this");
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
- if ((hapd->conf->p2p & P2P_ENABLED) && elems.p2p &&
- hapd->p2p_probe_resp_ie) {
- os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
- wpabuf_len(hapd->p2p_probe_resp_ie));
- pos += wpabuf_len(hapd->p2p_probe_resp_ie);
- }
-#endif /* CONFIG_P2P */
-#ifdef CONFIG_P2P_MANAGER
- if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
- P2P_MANAGE)
- pos = hostapd_eid_p2p_manage(hapd, pos);
-#endif /* CONFIG_P2P_MANAGER */
-
- if (hostapd_drv_send_mlme(hapd, resp, pos - (u8 *) resp) < 0)
- perror("handle_probe_req: send");
-
- os_free(resp);
-
- wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s "
- "SSID", MAC2STR(mgmt->sa),
- elems.ssid_len == 0 ? "broadcast" : "our");
+ if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie &&
+ !(hapd->iface->probe_resp_offloads &
+ WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P))
+ wpa_printf(MSG_WARNING, "Device is trying to offload P2P "
+ "Probe Response while not supporting this");
+#endif /* CONFIG_P2P */
+
+ if (hapd->conf->interworking &&
+ !(hapd->iface->probe_resp_offloads &
+ WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING))
+ wpa_printf(MSG_WARNING, "Device is trying to offload "
+ "Interworking Probe Response while not supporting "
+ "this");
+
+ /* Generate a Probe Response template for the non-P2P case */
+ return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len);
}
+#endif /* NEED_AP_MLME */
+
void ieee802_11_set_beacon(struct hostapd_data *hapd)
{
- struct ieee80211_mgmt *head;
- u8 *pos, *tail, *tailpos;
+ struct ieee80211_mgmt *head = NULL;
+ u8 *tail = NULL;
+ size_t head_len = 0, tail_len = 0;
+ u8 *resp = NULL;
+ size_t resp_len = 0;
+ struct wpa_driver_ap_params params;
+ struct wpabuf *beacon, *proberesp, *assocresp;
+#ifdef NEED_AP_MLME
u16 capab_info;
- size_t head_len, tail_len;
+ u8 *pos, *tailpos;
+#endif /* NEED_AP_MLME */
-#ifdef CONFIG_P2P
- if ((hapd->conf->p2p & (P2P_ENABLED | P2P_GROUP_OWNER)) == P2P_ENABLED)
- goto no_beacon;
-#endif /* CONFIG_P2P */
+ hapd->beacon_set_done = 1;
+
+#ifdef NEED_AP_MLME
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
@@ -474,7 +563,7 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
/* RSN, MDIE, WPA */
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
- tailpos, NULL);
+ tailpos);
#ifdef CONFIG_IEEE80211N
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
@@ -483,6 +572,16 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
tailpos = hostapd_eid_ext_capab(hapd, tailpos);
+ /*
+ * TODO: Time Advertisement element should only be included in some
+ * DTIM Beacon frames.
+ */
+ tailpos = hostapd_eid_time_adv(hapd, tailpos);
+
+ tailpos = hostapd_eid_interworking(hapd, tailpos);
+ tailpos = hostapd_eid_adv_proto(hapd, tailpos);
+ tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
+
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -509,20 +608,75 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
tail_len = tailpos > tail ? tailpos - tail : 0;
- if (hostapd_drv_set_beacon(hapd, (u8 *) head, head_len,
- tail, tail_len, hapd->conf->dtim_period,
- hapd->iconf->beacon_int))
- wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM "
- "period");
+ resp = hostapd_probe_resp_offloads(hapd, &resp_len);
+#endif /* NEED_AP_MLME */
+
+ os_memset(&params, 0, sizeof(params));
+ params.head = (u8 *) head;
+ params.head_len = head_len;
+ params.tail = tail;
+ params.tail_len = tail_len;
+ params.proberesp = resp;
+ params.proberesp_len = resp_len;
+ params.dtim_period = hapd->conf->dtim_period;
+ params.beacon_int = hapd->iconf->beacon_int;
+ params.basic_rates = hapd->iconf->basic_rates;
+ params.ssid = (u8 *) hapd->conf->ssid.ssid;
+ params.ssid_len = hapd->conf->ssid.ssid_len;
+ params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
+ hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
+ params.group_cipher = hapd->conf->wpa_group;
+ params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
+ params.auth_algs = hapd->conf->auth_algs;
+ params.wpa_version = hapd->conf->wpa;
+ params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+ (hapd->conf->ieee802_1x &&
+ (hapd->conf->default_wep_key_len ||
+ hapd->conf->individual_wep_key_len));
+ switch (hapd->conf->ignore_broadcast_ssid) {
+ case 0:
+ params.hide_ssid = NO_SSID_HIDING;
+ break;
+ case 1:
+ params.hide_ssid = HIDDEN_SSID_ZERO_LEN;
+ break;
+ case 2:
+ params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
+ break;
+ }
+ hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
+ params.beacon_ies = beacon;
+ params.proberesp_ies = proberesp;
+ params.assocresp_ies = assocresp;
+ params.isolate = hapd->conf->isolate;
+#ifdef NEED_AP_MLME
+ params.cts_protect = !!(ieee802_11_erp_info(hapd) &
+ ERP_INFO_USE_PROTECTION);
+ params.preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
+ hapd->iconf->preamble == SHORT_PREAMBLE;
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ params.short_slot_time =
+ hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
+ else
+ params.short_slot_time = -1;
+ if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+ params.ht_opmode = -1;
+ else
+ params.ht_opmode = hapd->iface->ht_op_mode;
+#endif /* NEED_AP_MLME */
+ params.interworking = hapd->conf->interworking;
+ if (hapd->conf->interworking &&
+ !is_zero_ether_addr(hapd->conf->hessid))
+ params.hessid = hapd->conf->hessid;
+ params.access_network_type = hapd->conf->access_network_type;
+ if (hostapd_drv_set_ap(hapd, &params))
+ wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
+ hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
os_free(tail);
os_free(head);
-
-#ifdef CONFIG_P2P
-no_beacon:
-#endif /* CONFIG_P2P */
- hostapd_set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) &
- ERP_INFO_USE_PROTECTION));
+ os_free(resp);
}
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index c1510e1..a944f5f 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -20,17 +20,7 @@ struct ieee80211_mgmt;
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len);
-#ifdef NEED_AP_MLME
void ieee802_11_set_beacon(struct hostapd_data *hapd);
void ieee802_11_set_beacons(struct hostapd_iface *iface);
-#else /* NEED_AP_MLME */
-static inline void ieee802_11_set_beacon(struct hostapd_data *hapd)
-{
-}
-
-static inline void ieee802_11_set_beacons(struct hostapd_iface *iface)
-{
-}
-#endif /* NEED_AP_MLME */
#endif /* BEACON_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 10e3af9..b7febdc 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -19,7 +19,6 @@
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
-#include "common/wpa_ctrl.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -28,25 +27,22 @@
#include "sta_info.h"
#include "accounting.h"
#include "tkip_countermeasures.h"
-#include "iapp.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
-#include "wmm.h"
#include "wps_hostapd.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
- const u8 *ie, size_t ielen, int reassoc)
+ const u8 *req_ies, size_t req_ies_len, int reassoc)
{
struct sta_info *sta;
int new_assoc, res;
struct ieee802_11_elems elems;
-#ifdef CONFIG_P2P
- const u8 *all_ies = ie;
- size_t all_ies_len = ielen;
-#endif /* CONFIG_P2P */
+ const u8 *ie;
+ size_t ielen;
+ u16 reason = WLAN_REASON_UNSPECIFIED;
if (addr == NULL) {
/*
@@ -65,7 +61,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "associated");
- ieee802_11_parse_elems(ie, ielen, &elems, 0);
+ ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
if (elems.wps_ie) {
ie = elems.wps_ie - 2;
ielen = elems.wps_ie_len + 2;
@@ -93,18 +89,19 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
if (sta == NULL)
return -1;
}
- sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
#ifdef CONFIG_P2P
if (elems.p2p) {
wpabuf_free(sta->p2p_ie);
- sta->p2p_ie = ieee802_11_vendor_ie_concat(all_ies, all_ies_len,
+ sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
P2P_IE_VENDOR_TYPE);
}
#endif /* CONFIG_P2P */
if (hapd->conf->wpa) {
if (ie == NULL || ielen == 0) {
+#ifdef CONFIG_WPS
if (hapd->conf->wps_state) {
wpa_printf(MSG_DEBUG, "STA did not include "
"WPA/RSN IE in (Re)Association "
@@ -112,15 +109,29 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->flags |= WLAN_STA_MAYBE_WPS;
goto skip_wpa_check;
}
+#endif /* CONFIG_WPS */
wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
return -1;
}
+#ifdef CONFIG_WPS
if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+ struct wpabuf *wps;
sta->flags |= WLAN_STA_WPS;
+ wps = ieee802_11_vendor_ie_concat(ie, ielen,
+ WPS_IE_VENDOR_TYPE);
+ if (wps) {
+ if (wps_is_20(wps)) {
+ wpa_printf(MSG_DEBUG, "WPS: STA "
+ "supports WPS 2.0");
+ sta->flags |= WLAN_STA_WPS2;
+ }
+ wpabuf_free(wps);
+ }
goto skip_wpa_check;
}
+#endif /* CONFIG_WPS */
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
@@ -133,52 +144,55 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
ie, ielen, NULL, 0);
if (res != WPA_IE_OK) {
- int resp;
wpa_printf(MSG_DEBUG, "WPA/RSN information element "
"rejected? (res %u)", res);
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
if (res == WPA_INVALID_GROUP)
- resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+ reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
else if (res == WPA_INVALID_PAIRWISE)
- resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+ reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
else if (res == WPA_INVALID_AKMP)
- resp = WLAN_REASON_AKMP_NOT_VALID;
+ reason = WLAN_REASON_AKMP_NOT_VALID;
#ifdef CONFIG_IEEE80211W
else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
- resp = WLAN_REASON_INVALID_IE;
+ reason = WLAN_REASON_INVALID_IE;
else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
- resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+ reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
#endif /* CONFIG_IEEE80211W */
else
- resp = WLAN_REASON_INVALID_IE;
- hostapd_drv_sta_disassoc(hapd, sta->addr, resp);
- ap_free_sta(hapd, sta);
- return -1;
+ reason = WLAN_REASON_INVALID_IE;
+ goto fail;
}
} else if (hapd->conf->wps_state) {
-#ifdef CONFIG_WPS_STRICT
- if (ie) {
- struct wpabuf *wps;
- wps = ieee802_11_vendor_ie_concat(ie, ielen,
+#ifdef CONFIG_WPS
+ struct wpabuf *wps;
+ if (req_ies)
+ wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
WPS_IE_VENDOR_TYPE);
- if (wps && wps_validate_assoc_req(wps) < 0) {
- hostapd_drv_sta_disassoc(
- hapd, sta->addr,
- WLAN_REASON_INVALID_IE);
- ap_free_sta(hapd, sta);
- wpabuf_free(wps);
- return -1;
- }
+ else
+ wps = NULL;
+#ifdef CONFIG_WPS_STRICT
+ if (wps && wps_validate_assoc_req(wps) < 0) {
+ reason = WLAN_REASON_INVALID_IE;
wpabuf_free(wps);
+ goto fail;
}
#endif /* CONFIG_WPS_STRICT */
- if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
- os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+ if (wps) {
sta->flags |= WLAN_STA_WPS;
+ if (wps_is_20(wps)) {
+ wpa_printf(MSG_DEBUG, "WPS: STA supports "
+ "WPS 2.0");
+ sta->flags |= WLAN_STA_WPS2;
+ }
} else
sta->flags |= WLAN_STA_MAYBE_WPS;
+ wpabuf_free(wps);
+#endif /* CONFIG_WPS */
}
+#ifdef CONFIG_WPS
skip_wpa_check:
+#endif /* CONFIG_WPS */
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
@@ -189,11 +203,18 @@ skip_wpa_check:
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
#ifdef CONFIG_P2P
- p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
- all_ies, all_ies_len);
+ if (req_ies) {
+ p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
+ req_ies, req_ies_len);
+ }
#endif /* CONFIG_P2P */
return 0;
+
+fail:
+ hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
+ ap_free_sta(hapd, sta);
+ return -1;
}
@@ -224,14 +245,8 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
return;
}
+ ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
- MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
- if(hapd->msg_ctx_parent)
- wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
- MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -255,8 +270,8 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
}
-int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
- const u8 *ie, size_t ie_len)
+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
+ const u8 *bssid, const u8 *ie, size_t ie_len)
{
size_t i;
int ret = 0;
@@ -267,7 +282,7 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
random_add_randomness(sa, ETH_ALEN);
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
- sa, ie, ie_len) > 0) {
+ sa, da, bssid, ie, ie_len) > 0) {
ret = 1;
break;
}
@@ -280,46 +295,6 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
#ifdef NEED_AP_MLME
-static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
-{
- u16 fc, type, stype;
-
- /*
- * PS-Poll frames are 16 bytes. All other frames are
- * 24 bytes or longer.
- */
- if (len < 16)
- return NULL;
-
- fc = le_to_host16(hdr->frame_control);
- type = WLAN_FC_GET_TYPE(fc);
- stype = WLAN_FC_GET_STYPE(fc);
-
- switch (type) {
- case WLAN_FC_TYPE_DATA:
- if (len < 24)
- return NULL;
- switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
- case WLAN_FC_FROMDS | WLAN_FC_TODS:
- case WLAN_FC_TODS:
- return hdr->addr1;
- case WLAN_FC_FROMDS:
- return hdr->addr2;
- default:
- return NULL;
- }
- case WLAN_FC_TYPE_CTRL:
- if (stype != WLAN_FC_STYPE_PSPOLL)
- return NULL;
- return hdr->addr1;
- case WLAN_FC_TYPE_MGMT:
- return hdr->addr3;
- default:
- return NULL;
- }
-}
-
-
#define HAPD_BROADCAST ((struct hostapd_data *) -1)
static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
@@ -343,17 +318,14 @@ static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
- const u8 *frame, size_t len)
+ const u8 *bssid, const u8 *addr,
+ int wds)
{
- const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
- u16 fc = le_to_host16(hdr->frame_control);
- hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
+ hapd = get_hapd_bssid(hapd->iface, bssid);
if (hapd == NULL || hapd == HAPD_BROADCAST)
return;
- ieee802_11_rx_from_unknown(hapd, hdr->addr2,
- (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
- (WLAN_FC_TODS | WLAN_FC_FROMDS));
+ ieee802_11_rx_from_unknown(hapd, addr, wds);
}
@@ -497,6 +469,23 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
struct hostapd_data *hapd = ctx;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ int level = MSG_DEBUG;
+
+ if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
+ data->rx_mgmt.frame_len >= 24) {
+ const struct ieee80211_hdr *hdr;
+ u16 fc;
+ hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+ fc = le_to_host16(hdr->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+ level = MSG_EXCESSIVE;
+ }
+
+ wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
+ event_to_string(event), event);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
switch (event) {
case EVENT_MICHAEL_MIC_FAILURE:
@@ -532,9 +521,19 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
}
break;
+ case EVENT_EAPOL_TX_STATUS:
+ hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
+ data->eapol_tx_status.data,
+ data->eapol_tx_status.data_len,
+ data->eapol_tx_status.ack);
+ break;
+ case EVENT_DRIVER_CLIENT_POLL_OK:
+ hostapd_client_poll_ok(hapd, data->client_poll.addr);
+ break;
case EVENT_RX_FROM_UNKNOWN:
- hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame,
- data->rx_from_unknown.len);
+ hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
+ data->rx_from_unknown.addr,
+ data->rx_from_unknown.wds);
break;
case EVENT_RX_MGMT:
hostapd_mgmt_rx(hapd, &data->rx_mgmt);
@@ -545,6 +544,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->rx_probe_req.ie == NULL)
break;
hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
+ data->rx_probe_req.da,
+ data->rx_probe_req.bssid,
data->rx_probe_req.ie,
data->rx_probe_req.ie_len);
break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index f00a544..0c5ee2e 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -61,9 +61,11 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
else
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
- if (hapd->conf->wpa && hapd->wpa_auth == NULL)
+ if (hapd->conf->wpa && hapd->wpa_auth == NULL) {
hostapd_setup_wpa(hapd);
- else if (hapd->conf->wpa) {
+ if (hapd->wpa_auth)
+ wpa_init_keys(hapd->wpa_auth);
+ } else if (hapd->conf->wpa) {
const u8 *wpa_ie;
size_t wpa_ie_len;
hostapd_reconfig_wpa(hapd);
@@ -259,6 +261,8 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
wpabuf_free(hapd->p2p_probe_resp_ie);
hapd->p2p_probe_resp_ie = NULL;
#endif /* CONFIG_P2P */
+
+ wpabuf_free(hapd->time_adv);
}
@@ -287,6 +291,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
iface->hw_features = NULL;
os_free(iface->current_rates);
iface->current_rates = NULL;
+ os_free(iface->basic_rates);
+ iface->basic_rates = NULL;
ap_list_deinit(iface);
hostapd_config_free(iface->conf);
iface->conf = NULL;
@@ -341,12 +347,13 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd)
if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
return 0;
- wpa_printf(MSG_DEBUG, "Flushing old station entries");
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries");
if (hostapd_flush(hapd)) {
- wpa_printf(MSG_WARNING, "Could not connect to kernel driver.");
+ wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to "
+ "kernel driver");
ret = -1;
}
- wpa_printf(MSG_DEBUG, "Deauthenticate all stations");
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
os_memset(addr, 0xff, ETH_ALEN);
hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_free_stas(hapd);
@@ -367,7 +374,6 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
u8 mask[ETH_ALEN] = { 0 };
struct hostapd_data *hapd = iface->bss[0];
unsigned int i = iface->conf->num_bss, bits = 0, j;
- int res;
int auto_addr = 0;
if (hostapd_drv_none(hapd))
@@ -431,17 +437,6 @@ skip_mask_ext:
wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
(unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
- res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask);
- if (res == 0)
- return 0;
-
- if (res < 0) {
- wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask "
- MACSTR " for start address " MACSTR ".",
- MAC2STR(mask), MAC2STR(hapd->own_addr));
- return -1;
- }
-
if (!auto_addr)
return 0;
@@ -639,6 +634,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
ieee802_11_set_beacon(hapd);
+ if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
+ return -1;
+
if (hapd->driver && hapd->driver->set_operstate)
hapd->driver->set_operstate(hapd->drv_priv, 1);
@@ -746,7 +744,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
}
if (iface->current_mode) {
- if (hostapd_prepare_rates(hapd, iface->current_mode)) {
+ if (hostapd_prepare_rates(iface, iface->current_mode)) {
wpa_printf(MSG_ERROR, "Failed to prepare rates "
"table.");
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 3764be4..c6f6205 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -31,7 +31,8 @@ enum wps_event;
union wps_event_data;
struct hostapd_probereq_cb {
- int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len);
+ int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
+ const u8 *ie, size_t ie_len);
void *ctx;
};
@@ -81,10 +82,7 @@ struct hostapd_data {
struct sta_info *sta, int reassoc);
void *msg_ctx; /* ctx for wpa_msg() calls */
-#ifdef ANDROID_BRCM_P2P_PATCH
- /* Sending the event to parent is required as SSL listens on parent ctrl iface */
- void *msg_ctx_parent; /* ctx for wpa_msg() calls */
-#endif /*ANDROID_BRCM_P2P_PATCH*/
+ void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */
struct radius_client_data *radius;
u32 acct_session_id_hi, acct_session_id_lo;
@@ -111,6 +109,10 @@ struct hostapd_data {
int parameter_set_count;
+ /* Time Advertisement */
+ u8 time_update_counter;
+ struct wpabuf *time_adv;
+
#ifdef CONFIG_FULL_DYNAMIC_VLAN
struct full_dynamic_vlan *full_dynamic_vlan;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -118,6 +120,7 @@ struct hostapd_data {
struct l2_packet_data *l2;
struct wps_context *wps;
+ int beacon_set_done;
struct wpabuf *wps_beacon_ie;
struct wpabuf *wps_probe_resp_ie;
#ifdef CONFIG_WPS
@@ -146,7 +149,7 @@ struct hostapd_data {
void *wps_event_cb_ctx;
void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
- int authorized);
+ int authorized, const u8 *p2p_dev_addr);
void *sta_authorized_cb_ctx;
void (*setup_complete_cb)(void *ctx);
@@ -189,6 +192,13 @@ struct hostapd_iface {
struct ap_info *ap_iter_list;
unsigned int drv_flags;
+
+ /*
+ * A bitmap of supported protocols for probe response offload. See
+ * struct wpa_driver_capa in driver.h
+ */
+ unsigned int probe_resp_offloads;
+
struct hostapd_hw_modes *hw_features;
int num_hw_features;
struct hostapd_hw_modes *current_mode;
@@ -196,6 +206,7 @@ struct hostapd_iface {
* current_mode->channels */
int num_rates;
struct hostapd_rate_data *current_rates;
+ int *basic_rates;
int freq;
u16 hw_flags;
@@ -251,6 +262,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
+ const u8 *da, const u8 *bssid,
const u8 *ie, size_t ie_len),
void *ctx);
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
@@ -260,7 +272,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ielen, int reassoc);
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
-int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
- const u8 *ie, size_t ie_len);
+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
+ const u8 *bssid, const u8 *ie, size_t ie_len);
#endif /* HOSTAPD_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 86f6811..8c6fef2 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -2,7 +2,7 @@
* hostapd / Hardware feature query and different modes
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -101,7 +101,7 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
}
-int hostapd_prepare_rates(struct hostapd_data *hapd,
+int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode)
{
int i, num_basic_rates = 0;
@@ -110,8 +110,8 @@ int hostapd_prepare_rates(struct hostapd_data *hapd,
int basic_rates_g[] = { 10, 20, 55, 110, -1 };
int *basic_rates;
- if (hapd->iconf->basic_rates)
- basic_rates = hapd->iconf->basic_rates;
+ if (iface->conf->basic_rates)
+ basic_rates = iface->conf->basic_rates;
else switch (mode->mode) {
case HOSTAPD_MODE_IEEE80211A:
basic_rates = basic_rates_a;
@@ -126,18 +126,20 @@ int hostapd_prepare_rates(struct hostapd_data *hapd,
return -1;
}
- if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
- basic_rates, mode->mode)) {
- wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel "
- "module");
- }
+ i = 0;
+ while (basic_rates[i] >= 0)
+ i++;
+ os_free(iface->basic_rates);
+ iface->basic_rates = os_malloc(i * sizeof(int));
+ if (iface->basic_rates)
+ os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int));
- os_free(hapd->iface->current_rates);
- hapd->iface->num_rates = 0;
+ os_free(iface->current_rates);
+ iface->num_rates = 0;
- hapd->iface->current_rates =
+ iface->current_rates =
os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data));
- if (!hapd->iface->current_rates) {
+ if (!iface->current_rates) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
"table.");
return -1;
@@ -146,27 +148,27 @@ int hostapd_prepare_rates(struct hostapd_data *hapd,
for (i = 0; i < mode->num_rates; i++) {
struct hostapd_rate_data *rate;
- if (hapd->iconf->supported_rates &&
- !hostapd_rate_found(hapd->iconf->supported_rates,
+ if (iface->conf->supported_rates &&
+ !hostapd_rate_found(iface->conf->supported_rates,
mode->rates[i]))
continue;
- rate = &hapd->iface->current_rates[hapd->iface->num_rates];
+ rate = &iface->current_rates[iface->num_rates];
rate->rate = mode->rates[i];
if (hostapd_rate_found(basic_rates, rate->rate)) {
rate->flags |= HOSTAPD_RATE_BASIC;
num_basic_rates++;
}
wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
- hapd->iface->num_rates, rate->rate, rate->flags);
- hapd->iface->num_rates++;
+ iface->num_rates, rate->rate, rate->flags);
+ iface->num_rates++;
}
- if ((hapd->iface->num_rates == 0 || num_basic_rates == 0) &&
- (!hapd->iconf->ieee80211n || !hapd->iconf->require_ht)) {
+ if ((iface->num_rates == 0 || num_basic_rates == 0) &&
+ (!iface->conf->ieee80211n || !iface->conf->require_ht)) {
wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
"rate sets (%d,%d).",
- hapd->iface->num_rates, num_basic_rates);
+ iface->num_rates, num_basic_rates);
return -1;
}
@@ -407,20 +409,6 @@ static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
}
-static void wpa_scan_results_free(struct wpa_scan_results *res)
-{
- size_t i;
-
- if (res == NULL)
- return;
-
- for (i = 0; i < res->num; i++)
- os_free(res->res[i]);
- os_free(res->res);
- os_free(res);
-}
-
-
static void ieee80211n_check_scan(struct hostapd_iface *iface)
{
struct wpa_scan_results *scan_res;
@@ -630,7 +618,8 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Hardware does not support configured mode "
- "(%d)", (int) iface->conf->hw_mode);
+ "(%d) (hw_mode in hostapd.conf)",
+ (int) iface->conf->hw_mode);
return -2;
}
@@ -642,8 +631,15 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
if (chan->flag & HOSTAPD_CHAN_DISABLED) {
wpa_printf(MSG_ERROR,
"channel [%i] (%i) is disabled for "
- "use in AP mode, flags: 0x%x",
- j, chan->chan, chan->flag);
+ "use in AP mode, flags: 0x%x%s%s%s",
+ j, chan->chan, chan->flag,
+ chan->flag & HOSTAPD_CHAN_NO_IBSS ?
+ " NO-IBSS" : "",
+ chan->flag &
+ HOSTAPD_CHAN_PASSIVE_SCAN ?
+ " PASSIVE-SCAN" : "",
+ chan->flag & HOSTAPD_CHAN_RADAR ?
+ " RADAR" : "");
} else {
ok = 1;
break;
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index b84bca6..abadcd1 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -2,6 +2,7 @@
* hostapd / Hardware feature query and different modes
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -25,7 +26,7 @@ const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
-int hostapd_prepare_rates(struct hostapd_data *hapd,
+int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
#else /* NEED_AP_MLME */
static inline void
@@ -59,7 +60,7 @@ static inline int hostapd_check_ht_capab(struct hostapd_iface *iface)
return 0;
}
-static inline int hostapd_prepare_rates(struct hostapd_data *hapd,
+static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode)
{
return 0;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index e0a3a36..a1a7270 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -163,59 +163,6 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
}
-u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
-{
- u8 *pos = eid;
-
- if ((hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) ==
- 0)
- return eid;
-
- *pos++ = WLAN_EID_EXT_CAPAB;
- *pos++ = 5;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos = 0x00;
- if (hapd->conf->tdls & TDLS_PROHIBIT)
- *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
- if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
- *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
- pos++;
-
- return pos;
-}
-
-
-#ifdef CONFIG_IEEE80211W
-static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
- struct sta_info *sta, u8 *eid)
-{
- u8 *pos = eid;
- u32 timeout, tu;
- struct os_time now, passed;
-
- *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
- *pos++ = 5;
- *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
- os_get_time(&now);
- os_time_sub(&now, &sta->sa_query_start, &passed);
- tu = (passed.sec * 1000000 + passed.usec) / 1024;
- if (hapd->conf->assoc_sa_query_max_timeout > tu)
- timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
- else
- timeout = 0;
- if (timeout < hapd->conf->assoc_sa_query_max_timeout)
- timeout++; /* add some extra time for local timers */
- WPA_PUT_LE32(pos, timeout);
- pos += 4;
-
- return pos;
-}
-#endif /* CONFIG_IEEE80211W */
-
-
void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
{
int i;
@@ -322,7 +269,7 @@ static void send_auth_reply(struct hostapd_data *hapd,
" auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
MAC2STR(dst), auth_alg, auth_transaction,
resp, (unsigned long) ies_len);
- if (hostapd_drv_send_mlme(hapd, reply, rlen) < 0)
+ if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
perror("send_auth_reply: send");
os_free(buf);
@@ -366,6 +313,8 @@ static void handle_auth(struct hostapd_data *hapd,
const u8 *challenge = NULL;
u32 session_timeout, acct_interim_interval;
int vlan_id = 0;
+ u8 psk[PMK_LEN];
+ int has_psk = 0;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
@@ -400,9 +349,7 @@ static void handle_auth(struct hostapd_data *hapd,
if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
auth_alg == WLAN_AUTH_OPEN) ||
#ifdef CONFIG_IEEE80211R
- (hapd->conf->wpa &&
- (hapd->conf->wpa_key_mgmt &
- (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) &&
+ (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
auth_alg == WLAN_AUTH_FT) ||
#endif /* CONFIG_IEEE80211R */
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
@@ -430,7 +377,9 @@ static void handle_auth(struct hostapd_data *hapd,
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
&session_timeout,
- &acct_interim_interval, &vlan_id);
+ &acct_interim_interval, &vlan_id,
+ psk, &has_psk);
+
if (res == HOSTAPD_ACL_REJECT) {
printf("Station " MACSTR " not allowed to authenticate.\n",
MAC2STR(mgmt->sa));
@@ -468,6 +417,16 @@ static void handle_auth(struct hostapd_data *hapd,
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
}
+ if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+ os_free(sta->psk);
+ sta->psk = os_malloc(PMK_LEN);
+ if (sta->psk)
+ os_memcpy(sta->psk, psk, PMK_LEN);
+ } else {
+ os_free(sta->psk);
+ sta->psk = NULL;
+ }
+
sta->flags &= ~WLAN_STA_PREAUTH;
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
@@ -592,15 +551,22 @@ static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *wmm_ie, size_t wmm_ie_len)
{
sta->flags &= ~WLAN_STA_WMM;
+ sta->qosinfo = 0;
if (wmm_ie && hapd->conf->wmm_enabled) {
- if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len))
+ struct wmm_information_element *wmm;
+
+ if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
"invalid WMM element in association "
"request");
- else
- sta->flags |= WLAN_STA_WMM;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_WMM;
+ wmm = (struct wmm_information_element *) wmm_ie;
+ sta->qosinfo = wmm->qos_info;
}
return WLAN_STATUS_SUCCESS;
}
@@ -701,7 +667,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
#ifdef CONFIG_WPS
- sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
if (hapd->conf->wps_state && elems.wps_ie) {
wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
"Request - assume WPS is used");
@@ -709,6 +675,10 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
wpabuf_free(sta->wps_ie);
sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
WPS_IE_VENDOR_TYPE);
+ if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
+ wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
+ sta->flags |= WLAN_STA_WPS2;
+ }
wpa_ie = NULL;
wpa_ie_len = 0;
if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
@@ -854,7 +824,7 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
reply.u.deauth.reason_code = host_to_le16(reason_code);
- if (hostapd_drv_send_mlme(hapd, &reply, send_len) < 0)
+ if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
wpa_printf(MSG_INFO, "Failed to send deauth: %s",
strerror(errno));
}
@@ -917,7 +887,8 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
p = hostapd_eid_wmm(hapd, p);
#ifdef CONFIG_WPS
- if (sta->flags & WLAN_STA_WPS) {
+ if ((sta->flags & WLAN_STA_WPS) ||
+ ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) {
struct wpabuf *wps = wps_build_assoc_resp_ie();
if (wps) {
os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
@@ -959,7 +930,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
send_len += p - reply->u.assoc_resp.variable;
- if (hostapd_drv_send_mlme(hapd, reply, send_len) < 0)
+ if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
strerror(errno));
}
@@ -1160,15 +1131,8 @@ static void handle_disassoc(struct hostapd_data *hapd,
return;
}
+ ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
- MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
- if(hapd->msg_ctx_parent)
- wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
- MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
-
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated");
@@ -1199,32 +1163,26 @@ static void handle_deauth(struct hostapd_data *hapd,
struct sta_info *sta;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
- wpa_msg(hapd, MSG_DEBUG, "handle_deauth - too short payload "
- "(len=%lu)", (unsigned long) len);
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
+ "payload (len=%lu)", (unsigned long) len);
return;
}
- wpa_msg(hapd, MSG_DEBUG, "deauthentication: STA=" MACSTR
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
" reason_code=%d",
MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
- wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " trying to "
- "deauthenticate, but it is not authenticated",
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
+ "to deauthenticate, but it is not authenticated",
MAC2STR(mgmt->sa));
return;
}
+ ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
WLAN_STA_ASSOC_REQ_OK);
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
- MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
- if(hapd->msg_ctx_parent)
- wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
- MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "deauthenticated");
@@ -1259,81 +1217,11 @@ static void handle_beacon(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211W
-/* MLME-SAQuery.request */
-void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
- const u8 *addr, const u8 *trans_id)
-{
- struct ieee80211_mgmt mgmt;
- u8 *end;
-
- wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
- MACSTR, MAC2STR(addr));
- wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
- trans_id, WLAN_SA_QUERY_TR_ID_LEN);
-
- os_memset(&mgmt, 0, sizeof(mgmt));
- mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- os_memcpy(mgmt.da, addr, ETH_ALEN);
- os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
- mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
- mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
- os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
- WLAN_SA_QUERY_TR_ID_LEN);
- end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
- if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt) < 0)
- perror("ieee802_11_send_sa_query_req: send");
-}
-
-
-static void hostapd_sa_query_request(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt)
-{
- struct sta_info *sta;
- struct ieee80211_mgmt resp;
- u8 *end;
-
- wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
- MACSTR, MAC2STR(mgmt->sa));
- wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
- mgmt->u.action.u.sa_query_resp.trans_id,
- WLAN_SA_QUERY_TR_ID_LEN);
-
- sta = ap_get_sta(hapd, mgmt->sa);
- if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
- "from unassociated STA " MACSTR, MAC2STR(mgmt->sa));
- return;
- }
-
- wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
- MACSTR, MAC2STR(mgmt->sa));
-
- os_memset(&resp, 0, sizeof(resp));
- resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- os_memcpy(resp.da, mgmt->sa, ETH_ALEN);
- os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
- resp.u.action.category = WLAN_ACTION_SA_QUERY;
- resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
- os_memcpy(resp.u.action.u.sa_query_req.trans_id,
- mgmt->u.action.u.sa_query_req.trans_id,
- WLAN_SA_QUERY_TR_ID_LEN);
- end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
- if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp) < 0)
- perror("hostapd_sa_query_request: send");
-}
-
-
static void hostapd_sa_query_action(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,
size_t len)
{
- struct sta_info *sta;
const u8 *end;
- int i;
end = mgmt->u.action.u.sa_query_resp.trans_id +
WLAN_SA_QUERY_TR_ID_LEN;
@@ -1343,50 +1231,9 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd,
return;
}
- if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) {
- hostapd_sa_query_request(hapd, mgmt);
- return;
- }
-
- if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
- "Action %d", mgmt->u.action.u.sa_query_resp.action);
- return;
- }
-
- wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
- MACSTR, MAC2STR(mgmt->sa));
- wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
- mgmt->u.action.u.sa_query_resp.trans_id,
- WLAN_SA_QUERY_TR_ID_LEN);
-
- /* MLME-SAQuery.confirm */
-
- sta = ap_get_sta(hapd, mgmt->sa);
- if (sta == NULL || sta->sa_query_trans_id == NULL) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
- "pending SA Query request found");
- return;
- }
-
- for (i = 0; i < sta->sa_query_count; i++) {
- if (os_memcmp(sta->sa_query_trans_id +
- i * WLAN_SA_QUERY_TR_ID_LEN,
- mgmt->u.action.u.sa_query_resp.trans_id,
- WLAN_SA_QUERY_TR_ID_LEN) == 0)
- break;
- }
-
- if (i >= sta->sa_query_count) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
- "transaction identifier found");
- return;
- }
-
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG,
- "Reply to pending SA Query received");
- ap_sta_stop_sa_query(hapd, sta);
+ ieee802_11_sa_query_action(hapd, mgmt->sa,
+ mgmt->u.action.u.sa_query_resp.action,
+ mgmt->u.action.u.sa_query_resp.trans_id);
}
@@ -1401,7 +1248,10 @@ static int robust_action_frame(u8 category)
static void handle_action(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
struct sta_info *sta;
+ sta = ap_get_sta(hapd, mgmt->sa);
+#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
if (len < IEEE80211_HDRLEN + 1) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -1411,7 +1261,6 @@ static void handle_action(struct hostapd_data *hapd,
return;
}
- sta = ap_get_sta(hapd, mgmt->sa);
#ifdef CONFIG_IEEE80211W
if (sta && (sta->flags & WLAN_STA_MFP) &&
!(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
@@ -1493,7 +1342,7 @@ static void handle_action(struct hostapd_data *hapd,
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
resp->u.action.category |= 0x80;
- hostapd_drv_send_mlme(hapd, resp, len);
+ hostapd_drv_send_mlme(hapd, resp, len, 0);
os_free(resp);
}
}
@@ -1536,6 +1385,11 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
if (!broadcast &&
+#ifdef CONFIG_P2P
+ /* Invitation responses can be sent with the peer MAC as BSSID */
+ !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+ stype == WLAN_FC_STYPE_ACTION) &&
+#endif /* CONFIG_P2P */
os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
printf("MGMT: BSSID=" MACSTR " not our address\n",
MAC2STR(mgmt->bssid));
@@ -1574,7 +1428,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
handle_disassoc(hapd, mgmt, len);
break;
case WLAN_FC_STYPE_DEAUTH:
- wpa_msg(hapd, MSG_DEBUG, "mgmt::deauth");
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
handle_deauth(hapd, mgmt, len);
break;
case WLAN_FC_STYPE_ACTION:
@@ -1688,14 +1542,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
* step.
*/
ap_sta_set_authorized(hapd, sta, 1);
- wpa_msg(hapd->msg_ctx, MSG_INFO,
- AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
- /* Sending the event to parent is required as SSL listens on parent ctrl iface */
- if(hapd->msg_ctx_parent)
- wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
- AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
}
if (reassoc)
@@ -1722,10 +1568,16 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
sta->supported_rates, sta->supported_rates_len,
sta->listen_interval,
- sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) {
+ sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+ sta->flags, sta->qosinfo)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
"Could not add STA to kernel driver");
+
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_DISASSOC_AP_BUSY);
+
+ goto fail;
}
if (sta->flags & WLAN_STA_WDS)
@@ -1764,6 +1616,54 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
}
+static void handle_deauth_cb(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int ok)
+{
+ struct sta_info *sta;
+ if (mgmt->da[0] & 0x01)
+ return;
+ sta = ap_get_sta(hapd, mgmt->da);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
+ " not found", MAC2STR(mgmt->da));
+ return;
+ }
+ if (ok)
+ wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
+ MAC2STR(sta->addr));
+ else
+ wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+ "deauth", MAC2STR(sta->addr));
+
+ ap_sta_deauth_cb(hapd, sta);
+}
+
+
+static void handle_disassoc_cb(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int ok)
+{
+ struct sta_info *sta;
+ if (mgmt->da[0] & 0x01)
+ return;
+ sta = ap_get_sta(hapd, mgmt->da);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
+ " not found", MAC2STR(mgmt->da));
+ return;
+ }
+ if (ok)
+ wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
+ MAC2STR(sta->addr));
+ else
+ wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+ "disassoc", MAC2STR(sta->addr));
+
+ ap_sta_disassoc_cb(hapd, sta);
+}
+
+
/**
* ieee802_11_mgmt_cb - Process management frame TX status callback
* @hapd: hostapd BSS data structure (the BSS from which the management frame
@@ -1796,7 +1696,12 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
break;
case WLAN_FC_STYPE_DEAUTH:
- /* ignore */
+ wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
+ handle_deauth_cb(hapd, mgmt, len, ok);
+ break;
+ case WLAN_FC_STYPE_DISASSOC:
+ wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
+ handle_disassoc_cb(hapd, mgmt, len, ok);
break;
case WLAN_FC_STYPE_ACTION:
wpa_printf(MSG_DEBUG, "mgmt::action cb");
@@ -1853,6 +1758,55 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
}
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+ const u8 *data, size_t len, int ack)
+{
+ struct sta_info *sta;
+ struct hostapd_iface *iface = hapd->iface;
+
+ sta = ap_get_sta(hapd, dst);
+ if (sta == NULL && iface->num_bss > 1) {
+ size_t j;
+ for (j = 0; j < iface->num_bss; j++) {
+ hapd = iface->bss[j];
+ sta = ap_get_sta(hapd, dst);
+ if (sta)
+ break;
+ }
+ }
+ if (sta == NULL)
+ return;
+
+ ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
+}
+
+
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
+{
+ struct sta_info *sta;
+ struct hostapd_iface *iface = hapd->iface;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL && iface->num_bss > 1) {
+ size_t j;
+ for (j = 0; j < iface->num_bss; j++) {
+ hapd = iface->bss[j];
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ break;
+ }
+ }
+ if (sta == NULL)
+ return;
+ if (!(sta->flags & WLAN_STA_PENDING_POLL))
+ return;
+
+ wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
+ "activity poll", MAC2STR(sta->addr));
+ sta->flags &= ~WLAN_STA_PENDING_POLL;
+}
+
+
void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
int wds)
{
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 157198c..43042a5 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -62,7 +62,21 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+ const u8 *data, size_t len, int ack);
void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
int wds);
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *eid);
+void ieee802_11_sa_query_action(struct hostapd_data *hapd,
+ const u8 *sa, const u8 action_type,
+ const u8 *trans_id);
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
+int hostapd_update_time_adv(struct hostapd_data *hapd);
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index b933263..f3f313d 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -21,6 +21,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "crypto/sha1.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
@@ -40,6 +41,8 @@ struct hostapd_cached_radius_acl {
u32 session_timeout;
u32 acct_interim_interval;
int vlan_id;
+ int has_psk;
+ u8 psk[PMK_LEN];
};
@@ -68,7 +71,8 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id)
+ u32 *acct_interim_interval, int *vlan_id,
+ u8 *psk, int *has_psk)
{
struct hostapd_cached_radius_acl *entry;
struct os_time now;
@@ -89,6 +93,10 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
entry->acct_interim_interval;
if (vlan_id)
*vlan_id = entry->vlan_id;
+ if (psk)
+ os_memcpy(psk, entry->psk, PMK_LEN);
+ if (has_psk)
+ *has_psk = entry->has_psk;
return entry->accepted;
}
@@ -210,11 +218,14 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
* @session_timeout: Buffer for returning session timeout (from RADIUS)
* @acct_interim_interval: Buffer for returning account interval (from RADIUS)
* @vlan_id: Buffer for returning VLAN ID
+ * @psk: Buffer for returning WPA PSK
+ * @has_psk: Buffer for indicating whether psk was filled
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id)
+ u32 *acct_interim_interval, int *vlan_id,
+ u8 *psk, int *has_psk)
{
if (session_timeout)
*session_timeout = 0;
@@ -222,6 +233,10 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
*acct_interim_interval = 0;
if (vlan_id)
*vlan_id = 0;
+ if (has_psk)
+ *has_psk = 0;
+ if (psk)
+ os_memset(psk, 0, PMK_LEN);
if (hostapd_maclist_found(hapd->conf->accept_mac,
hapd->conf->num_accept_mac, addr, vlan_id))
@@ -241,11 +256,12 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
return HOSTAPD_ACL_REJECT;
#else /* CONFIG_NO_RADIUS */
struct hostapd_acl_query_data *query;
+ struct os_time t;
/* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval,
- vlan_id);
+ vlan_id, psk, has_psk);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
@@ -271,7 +287,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
wpa_printf(MSG_ERROR, "malloc for query data failed");
return HOSTAPD_ACL_REJECT;
}
- time(&query->timestamp);
+ os_get_time(&t);
+ query->timestamp = t.sec;
os_memcpy(query->addr, addr, ETH_ALEN);
if (hostapd_radius_acl_query(hapd, addr, query)) {
wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
@@ -397,6 +414,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+ struct os_time t;
query = hapd->acl_queries;
prev = NULL;
@@ -431,9 +449,13 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
goto done;
}
- time(&cache->timestamp);
+ os_get_time(&t);
+ cache->timestamp = t.sec;
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
+ int passphraselen;
+ char *passphrase;
+
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
&cache->session_timeout) == 0)
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
@@ -452,6 +474,32 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
}
cache->vlan_id = radius_msg_get_vlanid(msg);
+
+ passphrase = radius_msg_get_tunnel_password(
+ msg, &passphraselen,
+ hapd->conf->radius->auth_server->shared_secret,
+ hapd->conf->radius->auth_server->shared_secret_len,
+ req);
+ cache->has_psk = passphrase != NULL;
+ if (passphrase != NULL) {
+ /* passphrase does not contain the NULL termination.
+ * Add it here as pbkdf2_sha1 requires it. */
+ char *strpassphrase = os_zalloc(passphraselen + 1);
+ if (strpassphrase) {
+ os_memcpy(strpassphrase, passphrase,
+ passphraselen);
+ pbkdf2_sha1(strpassphrase,
+ hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len, 4096,
+ cache->psk, PMK_LEN);
+ os_free(strpassphrase);
+ }
+ os_free(passphrase);
+ }
+
+ if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
+ cache->psk == NULL)
+ cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
cache->next = hapd->acl_cache;
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index b2971e5..a90571f 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -24,7 +24,8 @@ enum {
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id);
+ u32 *acct_interim_interval, int *vlan_id,
+ u8 *psk, int *has_psk);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
new file mode 100644
index 0000000..8503fce
--- /dev/null
+++ b/src/ap/ieee802_11_shared.c
@@ -0,0 +1,405 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "ieee802_11.h"
+
+
+#ifdef CONFIG_IEEE80211W
+
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *eid)
+{
+ u8 *pos = eid;
+ u32 timeout, tu;
+ struct os_time now, passed;
+
+ *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+ *pos++ = 5;
+ *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
+ os_get_time(&now);
+ os_time_sub(&now, &sta->sa_query_start, &passed);
+ tu = (passed.sec * 1000000 + passed.usec) / 1024;
+ if (hapd->conf->assoc_sa_query_max_timeout > tu)
+ timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
+ else
+ timeout = 0;
+ if (timeout < hapd->conf->assoc_sa_query_max_timeout)
+ timeout++; /* add some extra time for local timers */
+ WPA_PUT_LE32(pos, timeout);
+ pos += 4;
+
+ return pos;
+}
+
+
+/* MLME-SAQuery.request */
+void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
+ const u8 *addr, const u8 *trans_id)
+{
+ struct ieee80211_mgmt mgmt;
+ u8 *end;
+
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
+ MACSTR, MAC2STR(addr));
+ wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+ trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+ os_memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt.da, addr, ETH_ALEN);
+ os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+ mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
+ mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+ os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
+ WLAN_SA_QUERY_TR_ID_LEN);
+ end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+ if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
+ perror("ieee802_11_send_sa_query_req: send");
+}
+
+
+static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
+ const u8 *sa, const u8 *trans_id)
+{
+ struct sta_info *sta;
+ struct ieee80211_mgmt resp;
+ u8 *end;
+
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
+ MACSTR, MAC2STR(sa));
+ wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+ trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+ sta = ap_get_sta(hapd, sa);
+ if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
+ "from unassociated STA " MACSTR, MAC2STR(sa));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
+ MACSTR, MAC2STR(sa));
+
+ os_memset(&resp, 0, sizeof(resp));
+ resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(resp.da, sa, ETH_ALEN);
+ os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
+ resp.u.action.category = WLAN_ACTION_SA_QUERY;
+ resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
+ os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
+ WLAN_SA_QUERY_TR_ID_LEN);
+ end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+ if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
+ perror("ieee80211_mgmt_sa_query_request: send");
+}
+
+
+void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
+ const u8 action_type, const u8 *trans_id)
+{
+ struct sta_info *sta;
+ int i;
+
+ if (action_type == WLAN_SA_QUERY_REQUEST) {
+ ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
+ return;
+ }
+
+ if (action_type != WLAN_SA_QUERY_RESPONSE) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
+ "Action %d", action_type);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
+ MACSTR, MAC2STR(sa));
+ wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+ trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+ /* MLME-SAQuery.confirm */
+
+ sta = ap_get_sta(hapd, sa);
+ if (sta == NULL || sta->sa_query_trans_id == NULL) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
+ "pending SA Query request found");
+ return;
+ }
+
+ for (i = 0; i < sta->sa_query_count; i++) {
+ if (os_memcmp(sta->sa_query_trans_id +
+ i * WLAN_SA_QUERY_TR_ID_LEN,
+ trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0)
+ break;
+ }
+
+ if (i >= sta->sa_query_count) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
+ "transaction identifier found");
+ return;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Reply to pending SA Query received");
+ ap_sta_stop_sa_query(hapd, sta);
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
+u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+ u8 len = 0;
+
+ if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
+ len = 5;
+ if (len < 4 && hapd->conf->interworking)
+ len = 4;
+ if (len == 0)
+ return eid;
+
+ *pos++ = WLAN_EID_EXT_CAPAB;
+ *pos++ = len;
+ *pos++ = 0x00;
+ *pos++ = 0x00;
+ *pos++ = 0x00;
+
+ *pos = 0x00;
+ if (hapd->conf->time_advertisement == 2)
+ *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
+ if (hapd->conf->interworking)
+ *pos |= 0x80; /* Bit 31 - Interworking */
+ pos++;
+
+ if (len < 5)
+ return pos;
+ *pos = 0x00;
+ if (hapd->conf->tdls & TDLS_PROHIBIT)
+ *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+ if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
+ *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
+ pos++;
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+ u8 *len;
+
+ if (!hapd->conf->interworking)
+ return eid;
+
+ *pos++ = WLAN_EID_INTERWORKING;
+ len = pos++;
+
+ *pos = hapd->conf->access_network_type;
+ if (hapd->conf->internet)
+ *pos |= INTERWORKING_ANO_INTERNET;
+ if (hapd->conf->asra)
+ *pos |= INTERWORKING_ANO_ASRA;
+ if (hapd->conf->esr)
+ *pos |= INTERWORKING_ANO_ESR;
+ if (hapd->conf->uesa)
+ *pos |= INTERWORKING_ANO_UESA;
+ pos++;
+
+ if (hapd->conf->venue_info_set) {
+ *pos++ = hapd->conf->venue_group;
+ *pos++ = hapd->conf->venue_type;
+ }
+
+ if (!is_zero_ether_addr(hapd->conf->hessid)) {
+ os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
+ pos += ETH_ALEN;
+ }
+
+ *len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+
+ /* TODO: Separate configuration for ANQP? */
+ if (!hapd->conf->interworking)
+ return eid;
+
+ *pos++ = WLAN_EID_ADV_PROTO;
+ *pos++ = 2;
+ *pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */
+ *pos++ = ACCESS_NETWORK_QUERY_PROTOCOL;
+#endif /* CONFIG_INTERWORKING */
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+ u8 *len;
+ unsigned int i, count;
+
+ if (!hapd->conf->interworking ||
+ hapd->conf->roaming_consortium == NULL ||
+ hapd->conf->roaming_consortium_count == 0)
+ return eid;
+
+ *pos++ = WLAN_EID_ROAMING_CONSORTIUM;
+ len = pos++;
+
+ /* Number of ANQP OIs (in addition to the max 3 listed here) */
+ if (hapd->conf->roaming_consortium_count > 3 + 255)
+ *pos++ = 255;
+ else if (hapd->conf->roaming_consortium_count > 3)
+ *pos++ = hapd->conf->roaming_consortium_count - 3;
+ else
+ *pos++ = 0;
+
+ /* OU #1 and #2 Lengths */
+ *pos = hapd->conf->roaming_consortium[0].len;
+ if (hapd->conf->roaming_consortium_count > 1)
+ *pos |= hapd->conf->roaming_consortium[1].len << 4;
+ pos++;
+
+ if (hapd->conf->roaming_consortium_count > 3)
+ count = 3;
+ else
+ count = hapd->conf->roaming_consortium_count;
+
+ for (i = 0; i < count; i++) {
+ os_memcpy(pos, hapd->conf->roaming_consortium[i].oi,
+ hapd->conf->roaming_consortium[i].len);
+ pos += hapd->conf->roaming_consortium[i].len;
+ }
+
+ *len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid)
+{
+ if (hapd->conf->time_advertisement != 2)
+ return eid;
+
+ if (hapd->time_adv == NULL &&
+ hostapd_update_time_adv(hapd) < 0)
+ return eid;
+
+ if (hapd->time_adv == NULL)
+ return eid;
+
+ os_memcpy(eid, wpabuf_head(hapd->time_adv),
+ wpabuf_len(hapd->time_adv));
+ eid += wpabuf_len(hapd->time_adv);
+
+ return eid;
+}
+
+
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
+{
+ size_t len;
+
+ if (hapd->conf->time_advertisement != 2)
+ return eid;
+
+ len = os_strlen(hapd->conf->time_zone);
+
+ *eid++ = WLAN_EID_TIME_ZONE;
+ *eid++ = len;
+ os_memcpy(eid, hapd->conf->time_zone, len);
+ eid += len;
+
+ return eid;
+}
+
+
+int hostapd_update_time_adv(struct hostapd_data *hapd)
+{
+ const int elen = 2 + 1 + 10 + 5 + 1;
+ struct os_time t;
+ struct os_tm tm;
+ u8 *pos;
+
+ if (hapd->conf->time_advertisement != 2)
+ return 0;
+
+ if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0)
+ return -1;
+
+ if (!hapd->time_adv) {
+ hapd->time_adv = wpabuf_alloc(elen);
+ if (hapd->time_adv == NULL)
+ return -1;
+ pos = wpabuf_put(hapd->time_adv, elen);
+ } else
+ pos = wpabuf_mhead_u8(hapd->time_adv);
+
+ *pos++ = WLAN_EID_TIME_ADVERTISEMENT;
+ *pos++ = 1 + 10 + 5 + 1;
+
+ *pos++ = 2; /* UTC time at which the TSF timer is 0 */
+
+ /* Time Value at TSF 0 */
+ /* FIX: need to calculate this based on the current TSF value */
+ WPA_PUT_LE16(pos, tm.year); /* Year */
+ pos += 2;
+ *pos++ = tm.month; /* Month */
+ *pos++ = tm.day; /* Day of month */
+ *pos++ = tm.hour; /* Hours */
+ *pos++ = tm.min; /* Minutes */
+ *pos++ = tm.sec; /* Seconds */
+ WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */
+ pos += 2;
+ *pos++ = 0; /* Reserved */
+
+ /* Time Error */
+ /* TODO: fill in an estimate on the error */
+ *pos++ = 0;
+ *pos++ = 0;
+ *pos++ = 0;
+ *pos++ = 0;
+ *pos++ = 0;
+
+ *pos++ = hapd->time_update_counter++;
+
+ return 0;
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 49eba69..153b271 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -20,13 +20,13 @@
#include "crypto/crypto.h"
#include "crypto/random.h"
#include "common/ieee802_11_defs.h"
-#include "common/wpa_ctrl.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "eap_server/eap.h"
#include "eap_common/eap_wsc_common.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
+#include "p2p/p2p.h"
#include "hostapd.h"
#include "accounting.h"
#include "sta_info.h"
@@ -36,9 +36,6 @@
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "ieee802_1x.h"
-#ifdef ANDROID_BRCM_P2P_PATCH
-#include "p2p/p2p_i.h"
-#endif
static void ieee802_1x_finished(struct hostapd_data *hapd,
@@ -87,53 +84,16 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized)
{
int res;
-#ifdef ANDROID_BRCM_P2P_PATCH
- u8 *dev_addr = NULL;
-#endif
if (sta->flags & WLAN_STA_PREAUTH)
return;
if (authorized) {
- if (!ap_sta_is_authorized(sta)) {
-#if defined(ANDROID_BRCM_P2P_PATCH) && defined(CONFIG_P2P)
- if((dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr)))
- wpa_msg(hapd->msg_ctx, MSG_INFO,
- AP_STA_CONNECTED MACSTR " dev_addr="MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
- else
-#endif /*ANDROID_BRCM_P2P_PATCH*/
- wpa_msg(hapd->msg_ctx, MSG_INFO,
- AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-
-#ifdef ANDROID_BRCM_P2P_PATCH
- /* Sending the event to parent is required as SSL listens on parent ctrl iface */
- if(hapd->msg_ctx_parent) {
- if(dev_addr)
- wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
- AP_STA_CONNECTED MACSTR " dev_addr="MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
- else
- wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
- AP_STA_CONNECTED MACSTR , MAC2STR(sta->addr));
- }
-#endif /* ANDROID_BRCM_P2P_PATCH */
- }
-
ap_sta_set_authorized(hapd, sta, 1);
res = hostapd_set_authorized(hapd, sta, 1);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "authorizing port");
} else {
- if (ap_sta_is_authorized(sta) && (sta->flags & WLAN_STA_ASSOC)) {
- wpa_msg(hapd->msg_ctx, MSG_INFO,
- AP_STA_DISCONNECTED MACSTR,
- MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
- if(hapd->msg_ctx_parent)
- wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
- AP_STA_DISCONNECTED MACSTR,
- MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
- }
ap_sta_set_authorized(hapd, sta, 0);
res = hostapd_set_authorized(hapd, sta, 0);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
@@ -722,7 +682,8 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
(unsigned long) len, MAC2STR(sa));
sta = ap_get_sta(hapd, sa);
- if (!sta || !(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH))) {
+ if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
"associated/Pre-authenticating STA");
return;
@@ -785,14 +746,24 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
return;
#ifdef CONFIG_WPS
- if (!hapd->conf->ieee802_1x &&
- ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
- WLAN_STA_MAYBE_WPS)) {
- /*
- * Delay EAPOL frame transmission until a possible WPS
- * STA initiates the handshake with EAPOL-Start.
- */
- sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+ if (!hapd->conf->ieee802_1x) {
+ u32 wflags = sta->flags & (WLAN_STA_WPS |
+ WLAN_STA_WPS2 |
+ WLAN_STA_MAYBE_WPS);
+ if (wflags == WLAN_STA_MAYBE_WPS ||
+ wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) {
+ /*
+ * Delay EAPOL frame transmission until a
+ * possible WPS STA initiates the handshake
+ * with EAPOL-Start. Only allow the wait to be
+ * skipped if the STA is known to support WPS
+ * 2.0.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: Do not start "
+ "EAPOL until EAPOL-Start is "
+ "received");
+ sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+ }
}
#endif /* CONFIG_WPS */
@@ -921,11 +892,14 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
#ifdef CONFIG_WPS
sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
- if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) {
+ if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) {
/*
- * Delay EAPOL frame transmission until a possible WPS
- * initiates the handshake with EAPOL-Start.
+ * Delay EAPOL frame transmission until a possible WPS STA
+ * initiates the handshake with EAPOL-Start. Only allow the
+ * wait to be skipped if the STA is known to support WPS 2.0.
*/
+ wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
+ "EAPOL-Start is received");
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
#endif /* CONFIG_WPS */
@@ -1443,6 +1417,9 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
* request and we cannot continue EAP processing (EAP-Failure
* could only be sent if the EAP peer actually replied).
*/
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
+ MAC2STR(sta->addr));
+
sm->eap_if->portEnabled = FALSE;
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -1595,7 +1572,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
{
struct hostapd_data *hapd = ctx;
const struct hostapd_eap_user *eap_user;
- int i, count;
+ int i;
eap_user = hostapd_get_eap_user(hapd->conf, identity,
identity_len, phase2);
@@ -1604,10 +1581,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
os_memset(user, 0, sizeof(*user));
user->phase2 = phase2;
- count = EAP_USER_MAX_METHODS;
- if (count > EAP_MAX_METHODS)
- count = EAP_MAX_METHODS;
- for (i = 0; i < count; i++) {
+ for (i = 0; i < EAP_MAX_METHODS; i++) {
user->methods[i].vendor = eap_user->methods[i].vendor;
user->methods[i].method = eap_user->methods[i].method;
}
@@ -1619,6 +1593,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
os_memcpy(user->password, eap_user->password,
eap_user->password_len);
user->password_len = eap_user->password_len;
+ user->password_hash = eap_user->password_hash;
}
user->force_version = eap_user->force_version;
user->ttls_auth = eap_user->ttls_auth;
@@ -1795,15 +1770,13 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *buf, size_t len, int ack)
{
struct ieee80211_hdr *hdr;
- struct ieee802_1x_hdr *xhdr;
- struct ieee802_1x_eapol_key *key;
u8 *pos;
const unsigned char rfc1042_hdr[ETH_ALEN] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
if (sta == NULL)
return -1;
- if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr))
+ if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
return 0;
hdr = (struct ieee80211_hdr *) buf;
@@ -1815,16 +1788,30 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
return 0;
pos += 2;
- xhdr = (struct ieee802_1x_hdr *) pos;
- pos += sizeof(*xhdr);
+ return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos,
+ ack);
+}
+
+
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *buf, int len, int ack)
+{
+ const struct ieee802_1x_hdr *xhdr =
+ (const struct ieee802_1x_hdr *) buf;
+ const u8 *pos = buf + sizeof(*xhdr);
+ struct ieee802_1x_eapol_key *key;
+ if (len < (int) sizeof(*xhdr))
+ return 0;
wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
"type=%d length=%d - ack=%d",
MAC2STR(sta->addr), xhdr->version, xhdr->type,
be_to_host16(xhdr->length), ack);
- if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
- pos + sizeof(struct wpa_eapol_key) <= buf + len) {
+ if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
+ return 0;
+
+ if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
const struct wpa_eapol_key *wpa;
wpa = (const struct wpa_eapol_key *) pos;
if (wpa->type == EAPOL_KEY_TYPE_RSN ||
@@ -1835,11 +1822,10 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
/* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
* or Authenticator state machines, but EAPOL-Key packets are not
- * retransmitted in case of failure. Try to re-sent failed EAPOL-Key
+ * retransmitted in case of failure. Try to re-send failed EAPOL-Key
* packets couple of times because otherwise STA keys become
* unsynchronized with AP. */
- if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack &&
- pos + sizeof(*key) <= buf + len) {
+ if (!ack && pos + sizeof(*key) <= buf + len) {
key = (struct ieee802_1x_eapol_key *) pos;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
@@ -1943,6 +1929,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
{
int len = 0, ret;
struct eapol_state_machine *sm = sta->eapol_sm;
+ struct os_time t;
if (sm == NULL)
return 0;
@@ -2057,6 +2044,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
len += ret;
/* dot1xAuthSessionStatsTable */
+ os_get_time(&t);
ret = os_snprintf(buf + len, buflen - len,
/* TODO: dot1xAuthSessionOctetsRx */
/* TODO: dot1xAuthSessionOctetsTx */
@@ -2071,8 +2059,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
(wpa_key_mgmt_wpa_ieee8021x(
wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
1 : 2,
- (unsigned int) (time(NULL) -
- sta->acct_session_start),
+ (unsigned int) (t.sec - sta->acct_session_start),
sm->identity);
if (ret < 0 || (size_t) ret >= buflen - len)
return len;
@@ -2099,22 +2086,25 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
"Added PMKSA cache entry (IEEE 802.1X)");
}
-#ifdef CONFIG_WPS
- if (!success && (sta->flags & WLAN_STA_WPS)) {
+ if (!success) {
/*
* Many devices require deauthentication after WPS provisioning
* and some may not be be able to do that themselves, so
- * disconnect the client here.
+ * disconnect the client here. In addition, this may also
+ * benefit IEEE 802.1X/EAPOL authentication cases, too since
+ * the EAPOL PAE state machine would remain in HELD state for
+ * considerable amount of time and some EAP methods, like
+ * EAP-FAST with anonymous provisioning, may require another
+ * EAPOL authentication to be started to complete connection.
*/
- wpa_printf(MSG_DEBUG, "WPS: Force disconnection after "
- "EAP-Failure");
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
+ "disconnection after EAP-Failure");
/* Add a small sleep to increase likelihood of previously
* requested EAP-Failure TX getting out before this should the
* driver reorder operations.
*/
os_sleep(0, 10000);
ap_sta_disconnect(hapd, sta, sta->addr,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+ WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
}
-#endif /* CONFIG_WPS */
}
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 1a4d2eb..267e22a 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -68,6 +68,8 @@ int ieee802_1x_init(struct hostapd_data *hapd);
void ieee802_1x_deinit(struct hostapd_data *hapd);
int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *buf, size_t len, int ack);
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *data, int len, int ack);
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
int idx);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index e829447..972a723 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -1,6 +1,6 @@
/*
* hostapd / Station table
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "drivers/driver.h"
@@ -38,9 +39,12 @@
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta);
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
#ifdef CONFIG_IEEE80211W
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
#endif /* CONFIG_IEEE80211W */
+static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
int ap_for_each_sta(struct hostapd_data *hapd,
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
@@ -198,6 +202,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+ eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+ eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
ieee802_1x_free_station(sta);
wpa_auth_sta_deinit(sta->wpa_sm);
@@ -222,6 +228,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
wpabuf_free(sta->p2p_ie);
os_free(sta->ht_capabilities);
+ os_free(sta->psk);
os_free(sta);
}
@@ -275,31 +282,37 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
int inactive_sec;
inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
if (inactive_sec == -1) {
- wpa_msg(hapd, MSG_DEBUG, "Check inactivity: Could not "
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Check inactivity: Could not "
"get station info rom kernel driver for "
MACSTR, MAC2STR(sta->addr));
} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
sta->flags & WLAN_STA_ASSOC) {
/* station activity detected; reset timeout state */
- wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
- "active %is ago",
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Station " MACSTR " has been active %is ago",
MAC2STR(sta->addr), inactive_sec);
sta->timeout_next = STA_NULLFUNC;
next_time = hapd->conf->ap_max_inactivity -
inactive_sec;
} else {
- wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Station " MACSTR " has been "
"inactive too long: %d sec, max allowed: %d",
MAC2STR(sta->addr), inactive_sec,
hapd->conf->ap_max_inactivity);
+
+ if (hapd->conf->skip_inactivity_poll)
+ sta->timeout_next = STA_DISASSOC;
}
}
if ((sta->flags & WLAN_STA_ASSOC) &&
sta->timeout_next == STA_DISASSOC &&
- !(sta->flags & WLAN_STA_PENDING_POLL)) {
- wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has ACKed data "
- "poll", MAC2STR(sta->addr));
+ !(sta->flags & WLAN_STA_PENDING_POLL) &&
+ !hapd->conf->skip_inactivity_poll) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
+ " has ACKed data poll", MAC2STR(sta->addr));
/* data nullfunc frame poll did not produce TX errors; assume
* station ACKed it */
sta->timeout_next = STA_NULLFUNC;
@@ -314,46 +327,17 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
if (sta->timeout_next == STA_NULLFUNC &&
(sta->flags & WLAN_STA_ASSOC)) {
-#ifndef CONFIG_NATIVE_WINDOWS
- /* send data frame to poll STA and check whether this frame
- * is ACKed */
- struct ieee80211_hdr hdr;
-
- wpa_printf(MSG_DEBUG, " Polling STA with data frame");
+ wpa_printf(MSG_DEBUG, " Polling STA");
sta->flags |= WLAN_STA_PENDING_POLL;
-
- os_memset(&hdr, 0, sizeof(hdr));
- if (hapd->driver &&
- os_strcmp(hapd->driver->name, "hostap") == 0) {
- /*
- * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
- * but it is apparently not retried so TX Exc events
- * are not received for it.
- */
- hdr.frame_control =
- IEEE80211_FC(WLAN_FC_TYPE_DATA,
- WLAN_FC_STYPE_DATA);
- } else {
- hdr.frame_control =
- IEEE80211_FC(WLAN_FC_TYPE_DATA,
- WLAN_FC_STYPE_NULLFUNC);
- }
-
- hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
- os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
- os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
- ETH_ALEN);
- os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
-
- if (hostapd_drv_send_mlme(hapd, &hdr, sizeof(hdr)) < 0)
- perror("ap_handle_timer: send");
-#endif /* CONFIG_NATIVE_WINDOWS */
+ hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
+ sta->flags & WLAN_STA_WMM);
} else if (sta->timeout_next != STA_REMOVE) {
int deauth = sta->timeout_next == STA_DEAUTH;
- wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR,
- deauth ? "deauthentication" : "disassociation",
- MAC2STR(sta->addr));
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "Timeout, sending %s info to STA " MACSTR,
+ deauth ? "deauthentication" : "disassociation",
+ MAC2STR(sta->addr));
if (deauth) {
hostapd_drv_sta_deauth(
@@ -373,6 +357,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
hapd, sta);
break;
case STA_DISASSOC:
+ ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~WLAN_STA_ASSOC;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
if (!sta->acct_terminate_cause)
@@ -393,7 +378,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
case STA_REMOVE:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
- "inactivity");
+ "inactivity (timer DEAUTH/REMOVE)");
if (!sta->acct_terminate_cause)
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
@@ -525,13 +510,23 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
}
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = timeout_ctx;
+
+ ap_sta_remove(hapd, sta);
+ mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
+}
+
+
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
{
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->flags &= ~WLAN_STA_ASSOC;
- ap_sta_remove(hapd, sta);
+ ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_DEAUTH;
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
@@ -539,7 +534,22 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(sta);
- mlme_disassociate_indication(hapd, sta, reason);
+ sta->disassoc_reason = reason;
+ sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
+ eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+ eloop_register_timeout(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+ ap_sta_disassoc_cb_timeout, hapd, sta);
+}
+
+
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = timeout_ctx;
+
+ ap_sta_remove(hapd, sta);
+ mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
}
@@ -549,7 +559,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
- ap_sta_remove(hapd, sta);
+ ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_REMOVE;
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
@@ -557,7 +567,12 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(sta);
- mlme_deauthenticate_indication(hapd, sta, reason);
+ sta->deauth_reason = reason;
+ sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+ eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+ eloop_register_timeout(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+ ap_sta_deauth_cb_timeout, hapd, sta);
}
@@ -762,17 +777,58 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
{
+ const u8 *dev_addr = NULL;
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
return;
- if (authorized)
+#ifdef CONFIG_P2P
+ dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
+#endif /* CONFIG_P2P */
+
+ if (authorized) {
+ if (dev_addr)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+ MACSTR " p2p_dev_addr=" MACSTR,
+ MAC2STR(sta->addr), MAC2STR(dev_addr));
+ else
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+ MACSTR, MAC2STR(sta->addr));
+ if (hapd->msg_ctx_parent &&
+ hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+ wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+ AP_STA_CONNECTED MACSTR " p2p_dev_addr="
+ MACSTR,
+ MAC2STR(sta->addr), MAC2STR(dev_addr));
+ else if (hapd->msg_ctx_parent &&
+ hapd->msg_ctx_parent != hapd->msg_ctx)
+ wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+ AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
+
sta->flags |= WLAN_STA_AUTHORIZED;
- else
+ } else {
+ if (dev_addr)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+ MACSTR " p2p_dev_addr=" MACSTR,
+ MAC2STR(sta->addr), MAC2STR(dev_addr));
+ else
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+ MACSTR, MAC2STR(sta->addr));
+ if (hapd->msg_ctx_parent &&
+ hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+ wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+ AP_STA_DISCONNECTED MACSTR " p2p_dev_addr="
+ MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
+ else if (hapd->msg_ctx_parent &&
+ hapd->msg_ctx_parent != hapd->msg_ctx)
+ wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+ AP_STA_DISCONNECTED MACSTR,
+ MAC2STR(sta->addr));
sta->flags &= ~WLAN_STA_AUTHORIZED;
+ }
if (hapd->sta_authorized_cb)
hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
- sta->addr, authorized);
+ sta->addr, authorized, dev_addr);
}
@@ -791,6 +847,38 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
- eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
+ eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
+ ap_handle_timer, hapd, sta);
sta->timeout_next = STA_REMOVE;
+
+ sta->deauth_reason = reason;
+ sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+ eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+ eloop_register_timeout(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+ ap_sta_deauth_cb_timeout, hapd, sta);
+}
+
+
+void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) {
+ wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame");
+ return;
+ }
+ sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB;
+ eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+ ap_sta_deauth_cb_timeout(hapd, sta);
+}
+
+
+void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) {
+ wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame");
+ return;
+ }
+ sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB;
+ eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+ ap_sta_disassoc_cb_timeout(hapd, sta);
}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 9ec4fe3..daa96bf 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -1,6 +1,6 @@
/*
* hostapd / Station table
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -32,6 +32,9 @@
#define WLAN_STA_MAYBE_WPS BIT(13)
#define WLAN_STA_WDS BIT(14)
#define WLAN_STA_ASSOC_REQ_OK BIT(15)
+#define WLAN_STA_WPS2 BIT(16)
+#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
+#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
/* Maximum number of supported rates (from both Supported Rates and Extended
@@ -49,6 +52,7 @@ struct sta_info {
u16 listen_interval; /* or beacon_int for APs */
u8 supported_rates[WLAN_SUPP_RATES_MAX];
int supported_rates_len;
+ u8 qosinfo; /* Valid when WLAN_STA_WMM is set */
unsigned int nonerp_set:1;
unsigned int no_short_slot_time_set:1;
@@ -65,6 +69,9 @@ struct sta_info {
STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
} timeout_next;
+ u16 deauth_reason;
+ u16 disassoc_reason;
+
/* IEEE 802.1X related data */
struct eapol_state_machine *eapol_sm;
@@ -92,6 +99,7 @@ struct sta_info {
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
int vlan_id;
+ u8 *psk; /* PSK from RADIUS authentication server */
struct ieee80211_ht_capabilities *ht_capabilities;
@@ -114,7 +122,7 @@ struct sta_info {
* passed since last received frame from the station, a nullfunc data frame is
* sent to the station. If this frame is not acknowledged and no other frames
* have been received, the station will be disassociated after
- * AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated
+ * AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated
* after AP_DEAUTH_DELAY seconds has passed after disassociation. */
#define AP_MAX_INACTIVITY (5 * 60)
#define AP_DISASSOC_DELAY (1)
@@ -162,4 +170,7 @@ static inline int ap_sta_is_authorized(struct sta_info *sta)
return sta->flags & WLAN_STA_AUTHORIZED;
}
+void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
+
#endif /* STA_INFO_H */
diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c
index 1925217..fac7f4b 100644
--- a/src/ap/tkip_countermeasures.c
+++ b/src/ap/tkip_countermeasures.c
@@ -1,6 +1,6 @@
/*
* hostapd / TKIP countermeasures
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -60,9 +60,15 @@ static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
}
+void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
+{
+ eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
+}
+
+
void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
{
- time_t now;
+ struct os_time now;
if (addr && local) {
struct sta_info *sta = ap_get_sta(hapd, addr);
@@ -82,13 +88,13 @@ void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
}
}
- time(&now);
- if (now > hapd->michael_mic_failure + 60) {
+ os_get_time(&now);
+ if (now.sec > hapd->michael_mic_failure + 60) {
hapd->michael_mic_failures = 1;
} else {
hapd->michael_mic_failures++;
if (hapd->michael_mic_failures > 1)
ieee80211_tkip_countermeasures_start(hapd);
}
- hapd->michael_mic_failure = now;
+ hapd->michael_mic_failure = now.sec;
}
diff --git a/src/ap/tkip_countermeasures.h b/src/ap/tkip_countermeasures.h
index 5a1afce..a8ffd16 100644
--- a/src/ap/tkip_countermeasures.h
+++ b/src/ap/tkip_countermeasures.h
@@ -1,6 +1,6 @@
/*
* hostapd / TKIP countermeasures
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,5 +16,6 @@
#define TKIP_COUNTERMEASURES_H
void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
+void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd);
#endif /* TKIP_COUNTERMEASURES_H */
diff --git a/src/ap/utils.c b/src/ap/utils.c
index 0ff48ae..09bc32f 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -22,6 +22,7 @@
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
+ const u8 *da, const u8 *bssid,
const u8 *ie, size_t ie_len),
void *ctx)
{
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index a6d9b89..d21c82f 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -72,7 +72,8 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
wmm->version = WMM_VERSION;
wmm->qos_info = hapd->parameter_set_count & 0xf;
- if (hapd->conf->wmm_uapsd)
+ if (hapd->conf->wmm_uapsd &&
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
wmm->qos_info |= 0x80;
wmm->reserved = 0;
@@ -97,9 +98,11 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
}
-/* This function is called when a station sends an association request with
- * WMM info element. The function returns zero on success or non-zero on any
- * error in WMM element. eid does not include Element ID and Length octets. */
+/*
+ * This function is called when a station sends an association request with
+ * WMM info element. The function returns 1 on success or 0 on any error in WMM
+ * element. eid does not include Element ID and Length octets.
+ */
int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
{
struct wmm_information_element *wmm;
@@ -109,7 +112,7 @@ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
if (len < sizeof(struct wmm_information_element)) {
wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)",
(unsigned long) len);
- return -1;
+ return 0;
}
wmm = (struct wmm_information_element *) eid;
@@ -120,10 +123,10 @@ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT ||
wmm->version != WMM_VERSION) {
wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version");
- return -1;
+ return 0;
}
- return 0;
+ return 1;
}
@@ -153,7 +156,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
len = ((u8 *) (t + 1)) - buf;
- if (hostapd_drv_send_mlme(hapd, m, len) < 0)
+ if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
perror("wmm_send_action: send");
}
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 0836887..adc69e2 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
/*
- * hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * IEEE 802.11 RSN / WPA Authenticator
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -52,6 +52,7 @@ static const u32 dot11RSNAConfigGroupUpdateCount = 4;
static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
static const u32 eapol_key_timeout_first = 100; /* ms */
static const u32 eapol_key_timeout_subseq = 1000; /* ms */
+static const u32 eapol_key_timeout_first_group = 500; /* ms */
/* TODO: make these configurable */
static const int dot11RSNAConfigPMKLifetime = 43200;
@@ -194,6 +195,7 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
{
if (wpa_auth->cb.disconnect == NULL)
return;
+ wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr));
wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
}
@@ -332,7 +334,7 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
- int vlan_id)
+ int vlan_id, int delay_init)
{
struct wpa_group *group;
@@ -349,10 +351,6 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
"for secure operations - update keys later when "
"the first station connects");
-#ifdef ANDROID_BRCM_P2P_PATCH
- os_free(group);
- return NULL;
-#endif
}
/*
@@ -369,9 +367,15 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
}
group->GInit = TRUE;
- wpa_group_sm_step(wpa_auth, group);
- group->GInit = FALSE;
- wpa_group_sm_step(wpa_auth, group);
+ if (delay_init) {
+ wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
+ "until Beacon frames have been configured");
+ /* Initialization is completed in wpa_init_keys(). */
+ } else {
+ wpa_group_sm_step(wpa_auth, group);
+ group->GInit = FALSE;
+ wpa_group_sm_step(wpa_auth, group);
+ }
return group;
}
@@ -403,7 +407,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
return NULL;
}
- wpa_auth->group = wpa_group_init(wpa_auth, 0);
+ wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
if (wpa_auth->group == NULL) {
os_free(wpa_auth->wpa_ie);
os_free(wpa_auth);
@@ -444,6 +448,19 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
}
+int wpa_init_keys(struct wpa_authenticator *wpa_auth)
+{
+ struct wpa_group *group = wpa_auth->group;
+
+ wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
+ "keys");
+ wpa_group_sm_step(wpa_auth, group);
+ group->GInit = FALSE;
+ wpa_group_sm_step(wpa_auth, group);
+ return 0;
+}
+
+
/**
* wpa_deinit - Deinitialize WPA authenticator
* @wpa_auth: Pointer to WPA authenticator data from wpa_init()
@@ -695,6 +712,37 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_IEEE80211R */
+static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int group)
+{
+ /* Supplicant reported a Michael MIC error */
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key Error Request "
+ "(STA detected Michael MIC failure (group=%d))",
+ group);
+
+ if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "ignore Michael MIC failure report since "
+ "group cipher is not TKIP");
+ } else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "ignore Michael MIC failure report since "
+ "pairwise cipher is not TKIP");
+ } else {
+ wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+ sm->dot11RSNAStatsTKIPRemoteMICFailures++;
+ wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
+ }
+
+ /*
+ * Error report is not a request for a new key handshake, but since
+ * Authenticator may do it, let's change the keys now anyway.
+ */
+ wpa_request_new_ptk(sm);
+}
+
+
void wpa_receive(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
u8 *data, size_t data_len)
@@ -720,6 +768,9 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
key = (struct wpa_eapol_key *) (hdr + 1);
key_info = WPA_GET_BE16(key->key_info);
key_data_length = WPA_GET_BE16(key->key_data_length);
+ wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
+ " key_info=0x%x type=%u key_data_length=%u",
+ MAC2STR(sm->addr), key_info, key->type, key_data_length);
if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
"key_data overflow (%d > %lu)",
@@ -819,7 +870,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
if (!(key_info & WPA_KEY_INFO_REQUEST) &&
!wpa_replay_counter_valid(sm, key->replay_counter)) {
int i;
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
"received EAPOL-Key %s with unexpected "
"replay counter", msgtxt);
for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
@@ -1000,17 +1051,9 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_PEERKEY */
return;
} else if (key_info & WPA_KEY_INFO_ERROR) {
- /* Supplicant reported a Michael MIC error */
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Error Request "
- "(STA detected Michael MIC failure)");
- wpa_auth_mic_failure_report(wpa_auth, sm->addr);
- sm->dot11RSNAStatsTKIPRemoteMICFailures++;
- wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
- /* Error report is not a request for a new key
- * handshake, but since Authenticator may do it, let's
- * change the keys now anyway. */
- wpa_request_new_ptk(sm);
+ wpa_receive_error_report(
+ wpa_auth, sm,
+ !(key_info & WPA_KEY_INFO_KEY_TYPE));
} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key Request for new "
@@ -1028,9 +1071,6 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key Request for GTK "
"rekeying");
- /* FIX: why was this triggering PTK rekeying for the
- * STA that requested Group Key rekeying?? */
- /* wpa_request_new_ptk(sta->wpa_sm); */
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
wpa_rekey_gtk(wpa_auth, NULL);
}
@@ -1057,6 +1097,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
os_memcpy(sm->last_rx_eapol_key, data, data_len);
sm->last_rx_eapol_key_len = data_len;
+ sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
sm->EAPOLKeyReceived = TRUE;
sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
@@ -1293,7 +1334,8 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
if (ctr == 1 && wpa_auth->conf.tx_status)
- timeout_ms = eapol_key_timeout_first;
+ timeout_ms = pairwise ? eapol_key_timeout_first :
+ eapol_key_timeout_first_group;
else
timeout_ms = eapol_key_timeout_subseq;
if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
@@ -1844,6 +1886,20 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
gtk_len = 0;
keyidx = 0;
_rsc = NULL;
+ if (sm->rx_eapol_key_secure) {
+ /*
+ * It looks like Windows 7 supplicant tries to use
+ * Secure bit in msg 2/4 after having reported Michael
+ * MIC failure and it then rejects the 4-way handshake
+ * if msg 3/4 does not set Secure bit. Work around this
+ * by setting the Secure bit here even in the case of
+ * WPA if the supplicant used it first.
+ */
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "STA used Secure bit in WPA msg 2/4 - "
+ "set Secure for 3/4 as workaround");
+ secure = 1;
+ }
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
@@ -2469,6 +2525,7 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
group->GN_igtk = tmp;
#endif /* CONFIG_IEEE80211W */
wpa_gtk_update(wpa_auth, group);
+ wpa_group_config_group_keys(wpa_auth, group);
}
}
@@ -2771,7 +2828,7 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
vlan_id);
- group = wpa_group_init(wpa_auth, vlan_id);
+ group = wpa_group_init(wpa_auth, vlan_id, 0);
if (group == NULL)
return NULL;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index e533a14..ce2751e 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -208,6 +208,7 @@ struct wpa_auth_callbacks {
struct wpa_authenticator * wpa_init(const u8 *addr,
struct wpa_auth_config *conf,
struct wpa_auth_callbacks *cb);
+int wpa_init_keys(struct wpa_authenticator *wpa_auth);
void wpa_deinit(struct wpa_authenticator *wpa_auth);
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 65f5f4c..2d1bbe4 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -24,33 +24,10 @@
#include "wmm.h"
#include "wpa_auth.h"
#include "wpa_auth_i.h"
-#include "wpa_auth_ie.h"
#ifdef CONFIG_IEEE80211R
-struct wpa_ft_ies {
- const u8 *mdie;
- size_t mdie_len;
- const u8 *ftie;
- size_t ftie_len;
- const u8 *r1kh_id;
- const u8 *gtk;
- size_t gtk_len;
- const u8 *r0kh_id;
- size_t r0kh_id_len;
- const u8 *rsn;
- size_t rsn_len;
- const u8 *rsn_pmkid;
- const u8 *ric;
- size_t ric_len;
-};
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
- struct wpa_ft_ies *parse);
-
-
static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
const u8 *data, size_t data_len)
{
@@ -728,143 +705,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
}
-static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
- struct wpa_ft_ies *parse)
-{
- const u8 *end, *pos;
-
- parse->ftie = ie;
- parse->ftie_len = ie_len;
-
- pos = ie + sizeof(struct rsn_ftie);
- end = ie + ie_len;
-
- while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
- switch (pos[0]) {
- case FTIE_SUBELEM_R1KH_ID:
- if (pos[1] != FT_R1KH_ID_LEN) {
- wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
- "length in FTIE: %d", pos[1]);
- return -1;
- }
- parse->r1kh_id = pos + 2;
- break;
- case FTIE_SUBELEM_GTK:
- parse->gtk = pos + 2;
- parse->gtk_len = pos[1];
- break;
- case FTIE_SUBELEM_R0KH_ID:
- if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
- wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
- "length in FTIE: %d", pos[1]);
- return -1;
- }
- parse->r0kh_id = pos + 2;
- parse->r0kh_id_len = pos[1];
- break;
- }
-
- pos += 2 + pos[1];
- }
-
- return 0;
-}
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
- struct wpa_ft_ies *parse)
-{
- const u8 *end, *pos;
- struct wpa_ie_data data;
- int ret;
- const struct rsn_ftie *ftie;
- int prot_ie_count = 0;
-
- os_memset(parse, 0, sizeof(*parse));
- if (ies == NULL)
- return 0;
-
- pos = ies;
- end = ies + ies_len;
- while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
- switch (pos[0]) {
- case WLAN_EID_RSN:
- parse->rsn = pos + 2;
- parse->rsn_len = pos[1];
- ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
- parse->rsn_len + 2,
- &data);
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "FT: Failed to parse "
- "RSN IE: %d", ret);
- return -1;
- }
- if (data.num_pmkid == 1 && data.pmkid)
- parse->rsn_pmkid = data.pmkid;
- break;
- case WLAN_EID_MOBILITY_DOMAIN:
- parse->mdie = pos + 2;
- parse->mdie_len = pos[1];
- break;
- case WLAN_EID_FAST_BSS_TRANSITION:
- if (pos[1] < sizeof(*ftie))
- return -1;
- ftie = (const struct rsn_ftie *) (pos + 2);
- prot_ie_count = ftie->mic_control[1];
- if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
- return -1;
- break;
- case WLAN_EID_RIC_DATA:
- if (parse->ric == NULL)
- parse->ric = pos;
- }
-
- pos += 2 + pos[1];
- }
-
- if (prot_ie_count == 0)
- return 0; /* no MIC */
-
- /*
- * Check that the protected IE count matches with IEs included in the
- * frame.
- */
- if (parse->rsn)
- prot_ie_count--;
- if (parse->mdie)
- prot_ie_count--;
- if (parse->ftie)
- prot_ie_count--;
- if (prot_ie_count < 0) {
- wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
- "the protected IE count");
- return -1;
- }
-
- if (prot_ie_count == 0 && parse->ric) {
- wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
- "included in protected IE count");
- return -1;
- }
-
- /* Determine the end of the RIC IE(s) */
- pos = parse->ric;
- while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
- prot_ie_count) {
- prot_ie_count--;
- pos += 2 + pos[1];
- }
- parse->ric_len = pos - parse->ric;
- if (prot_ie_count) {
- wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
- "frame", (int) prot_ie_count);
- return -1;
- }
-
- return 0;
-}
-
-
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
@@ -1207,7 +1047,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
count = 3;
if (parse.ric)
- count++;
+ count += ieee802_11_ie_count(parse.ric, parse.ric_len);
if (ftie->mic_control[1] != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 0e3cb31..56bab23 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -29,11 +29,13 @@
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "wpa_auth.h"
+#include "wpa_auth_glue.h"
static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
struct wpa_auth_config *wconf)
{
+ os_memset(wconf, 0, sizeof(*wconf));
wconf->wpa = conf->wpa;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
wconf->wpa_pairwise = conf->wpa_pairwise;
@@ -184,6 +186,9 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
const u8 *prev_psk)
{
struct hostapd_data *hapd = ctx;
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ if (sta && sta->psk)
+ return sta->psk;
return hostapd_get_psk(hapd->conf, addr, prev_psk);
}
@@ -384,7 +389,7 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf,
sizeof(*buf) + data_len);
os_free(buf);
- return -1;
+ return ret;
}
@@ -414,7 +419,7 @@ static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
os_memcpy(&m->u, data, data_len);
- res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen);
+ res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
os_free(m);
return res;
}
@@ -547,6 +552,7 @@ void hostapd_reconfig_wpa(struct hostapd_data *hapd)
void hostapd_deinit_wpa(struct hostapd_data *hapd)
{
+ ieee80211_tkip_countermeasures_deinit(hapd);
rsn_preauth_iface_deinit(hapd);
if (hapd->wpa_auth) {
wpa_deinit(hapd->wpa_auth);
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 67a5c3b..d82192a 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -86,6 +86,7 @@ struct wpa_state_machine {
unsigned int pending_deinit:1;
unsigned int started:1;
unsigned int mgmt_frame_prot:1;
+ unsigned int rx_eapol_key_secure:1;
#ifdef CONFIG_IEEE80211R
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 9d4aa67..4db04bb 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -253,19 +253,10 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
capab |= WPA_CAPABILITY_PREAUTH;
if (conf->peerkey)
capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
-#ifdef ANDROID_BRCM_P2P_PATCH
- /* WAR: we should make an get_wpa_rsnie_cap() to get the cap of peer supp
- * Temporally we force tp set replay counter tp 0x3
- * as if wmm is enable in all of supp device
- */
- capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
-#else
if (conf->wmm_enabled) {
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#endif /* ANDROID_BRCM_P2P_PATCH */
-
#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
@@ -350,8 +341,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
pos += res;
}
#ifdef CONFIG_IEEE80211R
- if (wpa_auth->conf.wpa_key_mgmt &
- (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) {
+ if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
res = wpa_write_mdie(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
if (res < 0)
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 640e8cd..817012e 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -41,7 +41,8 @@ static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
#endif /* CONFIG_WPS_UPNP */
-static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
+ const u8 *bssid,
const u8 *ie, size_t ie_len);
static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
@@ -140,7 +141,8 @@ static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie,
hapd->wps_beacon_ie = beacon_ie;
wpabuf_free(hapd->wps_probe_resp_ie);
hapd->wps_probe_resp_ie = probe_resp_ie;
- ieee802_11_set_beacon(hapd);
+ if (hapd->beacon_set_done)
+ ieee802_11_set_beacon(hapd);
return hostapd_set_ap_wps_ie(hapd);
}
@@ -184,11 +186,26 @@ static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
}
+struct wps_stop_reg_data {
+ struct hostapd_data *current_hapd;
+ const u8 *uuid_e;
+};
+
+static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx)
+{
+ struct wps_stop_reg_data *data = ctx;
+ if (hapd != data->current_hapd && hapd->wps != NULL)
+ wps_registrar_complete(hapd->wps->registrar, data->uuid_e);
+ return 0;
+}
+
+
static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
const u8 *uuid_e)
{
struct hostapd_data *hapd = ctx;
char uuid[40];
+ struct wps_stop_reg_data data;
if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
return;
wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
@@ -196,6 +213,9 @@ static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
if (hapd->wps_reg_success_cb)
hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx,
mac_addr, uuid_e);
+ data.current_hapd = hapd;
+ data.uuid_e = uuid_e;
+ hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
}
@@ -240,6 +260,20 @@ static void wps_reload_config(void *eloop_data, void *user_ctx)
}
+static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
+ size_t attr_len)
+{
+ size_t blen = attr_len * 2 + 1;
+ char *buf = os_malloc(blen);
+ if (buf) {
+ wpa_snprintf_hex(buf, blen, attr, attr_len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ WPS_EVENT_NEW_AP_SETTINGS "%s", buf);
+ os_free(buf);
+ }
+}
+
+
static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
{
const struct wps_credential *cred = ctx;
@@ -269,15 +303,15 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
if ((hapd->conf->wps_cred_processing == 1 ||
hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
- size_t blen = cred->cred_attr_len * 2 + 1;
- char *_buf = os_malloc(blen);
- if (_buf) {
- wpa_snprintf_hex(_buf, blen,
- cred->cred_attr, cred->cred_attr_len);
- wpa_msg(hapd->msg_ctx, MSG_INFO, "%s%s",
- WPS_EVENT_NEW_AP_SETTINGS, _buf);
- os_free(_buf);
- }
+ hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len);
+ } else if (hapd->conf->wps_cred_processing == 1 ||
+ hapd->conf->wps_cred_processing == 2) {
+ struct wpabuf *attr;
+ attr = wpabuf_alloc(200);
+ if (attr && wps_build_credential_wrap(attr, cred) == 0)
+ hapd_new_ap_event(hapd, wpabuf_head_u8(attr),
+ wpabuf_len(attr));
+ wpabuf_free(attr);
} else
wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
@@ -565,18 +599,22 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
switch (event) {
case WPS_EV_M2D:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D);
break;
case WPS_EV_FAIL:
hostapd_wps_event_fail(hapd, &data->fail);
break;
case WPS_EV_SUCCESS:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS);
break;
case WPS_EV_PWD_AUTH_FAIL:
hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
break;
case WPS_EV_PBC_OVERLAP:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP);
break;
case WPS_EV_PBC_TIMEOUT:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT);
break;
case WPS_EV_ER_AP_ADD:
break;
@@ -762,8 +800,14 @@ int hostapd_init_wps(struct hostapd_data *hapd,
}
wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
- wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
- WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+
+ if (conf->wps_rf_bands) {
+ wps->dev.rf_bands = conf->wps_rf_bands;
+ } else {
+ wps->dev.rf_bands =
+ hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
+ WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+ }
if (conf->wpa & WPA_PROTO_RSN) {
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
@@ -1076,7 +1120,8 @@ error:
#endif /* CONFIG_WPS_OOB */
-static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
+ const u8 *bssid,
const u8 *ie, size_t ie_len)
{
struct hostapd_data *hapd = ctx;
@@ -1175,7 +1220,7 @@ static int hostapd_rx_req_put_wlan_response(
}
#endif /* CONFIG_WPS_STRICT */
- if (!sta) {
+ if (!sta || !(sta->flags & WLAN_STA_WPS)) {
wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
return 0;
}
@@ -1240,6 +1285,7 @@ static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
struct hostapd_data *hapd = eloop_data;
wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
hostapd_wps_ap_pin_disable(hapd);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED);
}
@@ -1304,7 +1350,7 @@ const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
struct wps_ap_pin_data data;
pin = wps_generate_pin();
- os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%u", pin);
+ os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
data.timeout = timeout;
hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
return hapd->conf->ap_pin;
diff --git a/src/common/defs.h b/src/common/defs.h
index 8abec07..6082053 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -76,6 +76,11 @@ static inline int wpa_key_mgmt_wpa(int akm)
wpa_key_mgmt_wpa_psk(akm);
}
+static inline int wpa_key_mgmt_wpa_any(int akm)
+{
+ return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
+}
+
#define WPA_PROTO_WPA BIT(0)
#define WPA_PROTO_RSN BIT(1)
@@ -267,4 +272,21 @@ enum hostapd_hw_mode {
NUM_HOSTAPD_MODES
};
+/**
+ * enum wpa_ctrl_req_type - Control interface request types
+ */
+enum wpa_ctrl_req_type {
+ WPA_CTRL_REQ_UNKNOWN,
+ WPA_CTRL_REQ_EAP_IDENTITY,
+ WPA_CTRL_REQ_EAP_PASSWORD,
+ WPA_CTRL_REQ_EAP_NEW_PASSWORD,
+ WPA_CTRL_REQ_EAP_PIN,
+ WPA_CTRL_REQ_EAP_OTP,
+ WPA_CTRL_REQ_EAP_PASSPHRASE,
+ NUM_WPA_CTRL_REQS
+};
+
+/* Maximum number of EAP methods to store for EAP server user information */
+#define EAP_MAX_METHODS 8
+
#endif /* DEFS_H */
diff --git a/src/common/gas.c b/src/common/gas.c
new file mode 100644
index 0000000..babdaa3
--- /dev/null
+++ b/src/common/gas.c
@@ -0,0 +1,279 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "ieee802_11_defs.h"
+#include "gas.h"
+
+
+static struct wpabuf *
+gas_build_req(u8 action, u8 dialog_token, size_t size)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(100 + size);
+ if (buf == NULL)
+ return NULL;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+ wpabuf_put_u8(buf, action);
+ wpabuf_put_u8(buf, dialog_token);
+
+ return buf;
+}
+
+
+static struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
+{
+ return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
+ size);
+}
+
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token)
+{
+ return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
+}
+
+
+static struct wpabuf *
+gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
+ u8 more, u16 comeback_delay, size_t size)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(100 + size);
+ if (buf == NULL)
+ return NULL;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+ wpabuf_put_u8(buf, action);
+ wpabuf_put_u8(buf, dialog_token);
+ wpabuf_put_le16(buf, status_code);
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
+ wpabuf_put_le16(buf, comeback_delay);
+
+ return buf;
+}
+
+
+struct wpabuf *
+gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
+ size_t size)
+{
+ return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
+ status_code, 0, 0, comeback_delay, size);
+}
+
+
+static struct wpabuf *
+gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
+ u16 comeback_delay, size_t size)
+{
+ return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
+ status_code, frag_id, more, comeback_delay,
+ size);
+}
+
+
+/**
+ * gas_add_adv_proto_anqp - Add an Advertisement Protocol element
+ * @buf: Buffer to which the element is added
+ * @query_resp_len_limit: Query Response Length Limit in units of 256 octets
+ * @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
+ *
+ *
+ * @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
+ * that the maximum limit is determined by the maximum allowable number of
+ * fragments in the GAS Query Response Fragment ID.
+ */
+static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
+ u8 pame_bi)
+{
+ /* Advertisement Protocol IE */
+ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(buf, 2); /* Length */
+ wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
+ (pame_bi ? 0x80 : 0));
+ /* Advertisement Protocol */
+ wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
+}
+
+
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
+{
+ struct wpabuf *buf;
+
+ buf = gas_build_initial_req(dialog_token, 4 + size);
+ if (buf == NULL)
+ return NULL;
+
+ gas_add_adv_proto_anqp(buf, 0, 0);
+
+ wpabuf_put(buf, 2); /* Query Request Length to be filled */
+
+ return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+ u16 comeback_delay, size_t size)
+{
+ struct wpabuf *buf;
+
+ buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
+ 4 + size);
+ if (buf == NULL)
+ return NULL;
+
+ gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+ wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+ return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+ u16 status_code,
+ u16 comeback_delay,
+ struct wpabuf *payload)
+{
+ struct wpabuf *buf;
+
+ buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+ comeback_delay,
+ payload ? wpabuf_len(payload) : 0);
+ if (buf == NULL)
+ return NULL;
+
+ if (payload)
+ wpabuf_put_buf(buf, payload);
+
+ gas_anqp_set_len(buf);
+
+ return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+ u8 frag_id, u8 more,
+ u16 comeback_delay, size_t size)
+{
+ struct wpabuf *buf;
+
+ buf = gas_build_comeback_resp(dialog_token, status_code,
+ frag_id, more, comeback_delay, 4 + size);
+ if (buf == NULL)
+ return NULL;
+
+ gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+ wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+ return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+ u16 status_code,
+ u8 frag_id, u8 more,
+ u16 comeback_delay,
+ struct wpabuf *payload)
+{
+ struct wpabuf *buf;
+
+ buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+ more, comeback_delay,
+ payload ? wpabuf_len(payload) : 0);
+ if (buf == NULL)
+ return NULL;
+
+ if (payload)
+ wpabuf_put_buf(buf, payload);
+
+ gas_anqp_set_len(buf);
+
+ return buf;
+}
+
+
+/**
+ * gas_anqp_set_len - Set Query Request/Response Length
+ * @buf: GAS message
+ *
+ * This function is used to update the Query Request/Response Length field once
+ * the payload has been filled.
+ */
+void gas_anqp_set_len(struct wpabuf *buf)
+{
+ u8 action;
+ size_t offset;
+ u8 *len;
+
+ if (buf == NULL || wpabuf_len(buf) < 2)
+ return;
+
+ action = *(wpabuf_head_u8(buf) + 1);
+ switch (action) {
+ case WLAN_PA_GAS_INITIAL_REQ:
+ offset = 3 + 4;
+ break;
+ case WLAN_PA_GAS_INITIAL_RESP:
+ offset = 7 + 4;
+ break;
+ case WLAN_PA_GAS_COMEBACK_RESP:
+ offset = 8 + 4;
+ break;
+ default:
+ return;
+ }
+
+ if (wpabuf_len(buf) < offset + 2)
+ return;
+
+ len = wpabuf_mhead_u8(buf) + offset;
+ WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+}
+
+
+/**
+ * gas_anqp_add_element - Add ANQP element header
+ * @buf: GAS message
+ * @info_id: ANQP Info ID
+ * Returns: Pointer to the Length field for gas_anqp_set_element_len()
+ */
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
+{
+ wpabuf_put_le16(buf, info_id);
+ return wpabuf_put(buf, 2); /* Length to be filled */
+}
+
+
+/**
+ * gas_anqp_set_element_len - Update ANQP element Length field
+ * @buf: GAS message
+ * @len_pos: Length field position from gas_anqp_add_element()
+ *
+ * This function is called after the ANQP element payload has been added to the
+ * buffer.
+ */
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
+{
+ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+}
diff --git a/src/common/gas.h b/src/common/gas.h
new file mode 100644
index 0000000..2f8d2cb
--- /dev/null
+++ b/src/common/gas.h
@@ -0,0 +1,42 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef GAS_H
+#define GAS_H
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token);
+struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code,
+ u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+ u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+ u16 status_code,
+ u16 comeback_delay,
+ struct wpabuf *payload);
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+ u8 frag_id, u8 more,
+ u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+ u16 status_code,
+ u8 frag_id, u8 more,
+ u16 comeback_delay,
+ struct wpabuf *payload);
+void gas_anqp_set_len(struct wpabuf *buf);
+
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id);
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos);
+
+#endif /* GAS_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index ee41b3a..43cb2c6 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -259,6 +259,10 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
break;
elems->link_id = pos;
break;
+ case WLAN_EID_INTERWORKING:
+ elems->interworking = pos;
+ elems->interworking_len = elen;
+ break;
default:
unknown++;
if (!show_errors)
@@ -345,3 +349,43 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
return buf;
}
+
+
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
+{
+ u16 fc, type, stype;
+
+ /*
+ * PS-Poll frames are 16 bytes. All other frames are
+ * 24 bytes or longer.
+ */
+ if (len < 16)
+ return NULL;
+
+ fc = le_to_host16(hdr->frame_control);
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ switch (type) {
+ case WLAN_FC_TYPE_DATA:
+ if (len < 24)
+ return NULL;
+ switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
+ case WLAN_FC_FROMDS | WLAN_FC_TODS:
+ case WLAN_FC_TODS:
+ return hdr->addr1;
+ case WLAN_FC_FROMDS:
+ return hdr->addr2;
+ default:
+ return NULL;
+ }
+ case WLAN_FC_TYPE_CTRL:
+ if (stype != WLAN_FC_STYPE_PSPOLL)
+ return NULL;
+ return hdr->addr1;
+ case WLAN_FC_TYPE_MGMT:
+ return hdr->addr3;
+ default:
+ return NULL;
+ }
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 0c90fa4..60f0974 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -42,6 +42,7 @@ struct ieee802_11_elems {
const u8 *vendor_ht_cap;
const u8 *p2p;
const u8 *link_id;
+ const u8 *interworking;
u8 ssid_len;
u8 supp_rates_len;
@@ -67,6 +68,7 @@ struct ieee802_11_elems {
u8 ht_operation_len;
u8 vendor_ht_cap_len;
u8 p2p_len;
+ u8 interworking_len;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -77,5 +79,7 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
u32 oui_type);
+struct ieee80211_hdr;
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len);
#endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 86868c0..66801fd 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -153,7 +153,17 @@
#define WLAN_STATUS_INVALID_PMKID 53
#define WLAN_STATUS_INVALID_MDIE 54
#define WLAN_STATUS_INVALID_FTIE 55
+#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59
+#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60
+#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61
+#define WLAN_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62
+#define WLAN_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63
+#define WLAN_STATUS_REQ_REFUSED_HOME 64
+#define WLAN_STATUS_ADV_SRV_UNREACHABLE 65
+#define WLAN_STATUS_REQ_REFUSED_SSPN 67
+#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
#define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_TRANSMISSION_FAILURE 79
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
#define WLAN_REASON_UNSPECIFIED 1
@@ -219,12 +229,16 @@
#define WLAN_EID_RIC_DATA 57
#define WLAN_EID_HT_OPERATION 61
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_TIME_ADVERTISEMENT 69
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
#define WLAN_EID_MMIE 76
+#define WLAN_EID_TIME_ZONE 98
#define WLAN_EID_LINK_ID 101
+#define WLAN_EID_INTERWORKING 107
#define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_ROAMING_CONSORTIUM 111
#define WLAN_EID_EXT_CAPAB 127
#define WLAN_EID_VENDOR_SPECIFIC 221
@@ -239,6 +253,8 @@
#define WLAN_ACTION_FT 6
#define WLAN_ACTION_HT 7
#define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_WNM 10
+#define WLAN_ACTION_UNPROTECTED_WNM 11
#define WLAN_ACTION_TDLS 12
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
#define WLAN_ACTION_VENDOR_SPECIFIC 127
@@ -249,6 +265,7 @@
#define WLAN_PA_GAS_INITIAL_RESP 11
#define WLAN_PA_GAS_COMEBACK_REQ 12
#define WLAN_PA_GAS_COMEBACK_RESP 13
+#define WLAN_TDLS_DISCOVERY_RESPONSE 14
/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
#define WLAN_SA_QUERY_REQUEST 0
@@ -274,33 +291,81 @@
#define WLAN_TIMEOUT_KEY_LIFETIME 2
#define WLAN_TIMEOUT_ASSOC_COMEBACK 3
-/* Advertisement Protocol ID definitions (IEEE 802.11u) */
+/* Interworking element (IEEE 802.11u) - Access Network Options */
+#define INTERWORKING_ANO_ACCESS_NETWORK_MASK 0x0f
+#define INTERWORKING_ANO_INTERNET 0x10
+#define INTERWORKING_ANO_ASRA 0x20
+#define INTERWORKING_ANO_ESR 0x40
+#define INTERWORKING_ANO_UESA 0x80
+
+#define INTERWORKING_ANT_PRIVATE 0
+#define INTERWORKING_ANT_PRIVATE_WITH_GUEST 1
+#define INTERWORKING_ANT_CHARGEABLE_PUBLIC 2
+#define INTERWORKING_ANT_FREE_PUBLIC 3
+#define INTERWORKING_ANT_PERSONAL_DEVICE 4
+#define INTERWORKING_ANT_EMERGENCY_SERVICES 5
+#define INTERWORKING_ANT_TEST 6
+#define INTERWORKING_ANT_WILDCARD 15
+
+/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */
enum adv_proto_id {
- NATIVE_QUERY_PROTOCOL = 0,
+ ACCESS_NETWORK_QUERY_PROTOCOL = 0,
MIH_INFO_SERVICE = 1,
MIH_CMD_AND_EVENT_DISCOVERY = 2,
EMERGENCY_ALERT_SYSTEM = 3,
- LOCATION_TO_SERVICE = 4,
ADV_PROTO_VENDOR_SPECIFIC = 221
};
-/* Native Query Protocol info ID definitions (IEEE 802.11u) */
-enum nqp_info_id {
- NQP_CAPABILITY_LIST = 256,
- NQP_VENUE_NAME = 257,
- NQP_EMERGENCY_CALL_NUMBER = 258,
- NQP_NETWORK_AUTH_TYPE = 259,
- NQP_ROAMING_CONSORTIUM = 260,
- NQP_IP_ADDR_TYPE_AVAILABILITY = 261,
- NQP_NAI_REALM = 262,
- NQP_3GPP_CELLULAR_NETWORK = 263,
- NQP_AP_GEOSPATIAL_LOCATION = 264,
- NQP_AP_CIVIC_LOCATION = 265,
- NQP_DOMAIN_NAME = 266,
- NQP_EMERGENCY_ALERT_URI = 267,
- NQP_VENDOR_SPECIFIC = 56797
+/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */
+enum anqp_info_id {
+ ANQP_QUERY_LIST = 256,
+ ANQP_CAPABILITY_LIST = 257,
+ ANQP_VENUE_NAME = 258,
+ ANQP_EMERGENCY_CALL_NUMBER = 259,
+ ANQP_NETWORK_AUTH_TYPE = 260,
+ ANQP_ROAMING_CONSORTIUM = 261,
+ ANQP_IP_ADDR_TYPE_AVAILABILITY = 262,
+ ANQP_NAI_REALM = 263,
+ ANQP_3GPP_CELLULAR_NETWORK = 264,
+ ANQP_AP_GEOSPATIAL_LOCATION = 265,
+ ANQP_AP_CIVIC_LOCATION = 266,
+ ANQP_AP_LOCATION_PUBLIC_URI = 267,
+ ANQP_DOMAIN_NAME = 268,
+ ANQP_EMERGENCY_ALERT_URI = 269,
+ ANQP_EMERGENCY_NAI = 271,
+ ANQP_VENDOR_SPECIFIC = 56797
};
+/* NAI Realm list - EAP Method subfield - Authentication Parameter ID */
+enum nai_realm_eap_auth_param {
+ NAI_REALM_EAP_AUTH_EXPANDED_EAP_METHOD = 1,
+ NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH = 2,
+ NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD = 3,
+ NAI_REALM_EAP_AUTH_EXPANDED_INNER_EAP_METHOD = 4,
+ NAI_REALM_EAP_AUTH_CRED_TYPE = 5,
+ NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE = 6,
+ NAI_REALM_EAP_AUTH_VENDOR_SPECIFIC = 221
+};
+
+enum nai_realm_eap_auth_inner_non_eap {
+ NAI_REALM_INNER_NON_EAP_PAP = 1,
+ NAI_REALM_INNER_NON_EAP_CHAP = 2,
+ NAI_REALM_INNER_NON_EAP_MSCHAP = 3,
+ NAI_REALM_INNER_NON_EAP_MSCHAPV2 = 4
+};
+
+enum nai_realm_eap_cred_type {
+ NAI_REALM_CRED_TYPE_SIM = 1,
+ NAI_REALM_CRED_TYPE_USIM = 2,
+ NAI_REALM_CRED_TYPE_NFC_SECURE_ELEMENT = 3,
+ NAI_REALM_CRED_TYPE_HARDWARE_TOKEN = 4,
+ NAI_REALM_CRED_TYPE_SOFTOKEN = 5,
+ NAI_REALM_CRED_TYPE_CERTIFICATE = 6,
+ NAI_REALM_CRED_TYPE_USERNAME_PASSWORD = 7,
+ NAI_REALM_CRED_TYPE_NONE = 8,
+ NAI_REALM_CRED_TYPE_ANONYMOUS = 9,
+ NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
+};
#ifdef _MSC_VER
#pragma pack(push, 1)
@@ -436,6 +501,18 @@ struct ieee80211_mgmt {
/* Vendor-specific content */
u8 variable[0];
} STRUCT_PACKED vs_public_action;
+ struct {
+ u8 action; /* 7 */
+ u8 dialog_token;
+ u8 req_mode;
+ le16 disassoc_timer;
+ u8 validity_interval;
+ /* BSS Termination Duration (optional),
+ * Session Information URL (optional),
+ * BSS Transition Candidate List
+ * Entries */
+ u8 variable[0];
+ } STRUCT_PACKED bss_tm_req;
} u;
} STRUCT_PACKED action;
} u;
@@ -541,7 +618,7 @@ struct ieee80211_ht_operation {
#define OP_MODE_MIXED 3
#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \
- ((le16) (0x0001 | 0x0002))
+ (0x0001 | 0x0002)
#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0
#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2))
#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3))
@@ -600,6 +677,10 @@ struct wmm_information_element {
} STRUCT_PACKED;
+#define WMM_QOSINFO_STA_AC_MASK 0x0f
+#define WMM_QOSINFO_STA_SP_MASK 0x03
+#define WMM_QOSINFO_STA_SP_SHIFT 5
+
#define WMM_AC_AIFSN_MASK 0x0f
#define WMM_AC_AIFNS_SHIFT 0
#define WMM_AC_ACM 0x10
@@ -628,7 +709,7 @@ struct wmm_parameter_element {
u8 oui_type; /* 2 */
u8 oui_subtype; /* 1 */
u8 version; /* 1 for WMM version 1.0 */
- u8 qos_info; /* AP/STA specif QoS info */
+ u8 qos_info; /* AP/STA specific QoS info */
u8 reserved; /* 0 */
struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
@@ -797,4 +878,44 @@ enum p2p_sd_status {
#define WLAN_AKM_SUITE_8021X 0x000FAC01
#define WLAN_AKM_SUITE_PSK 0x000FAC02
+
+/* IEEE 802.11v - WNM Action field values */
+enum wnm_action {
+ WNM_EVENT_REQ = 0,
+ WNM_EVENT_REPORT = 1,
+ WNM_DIAGNOSTIC_REQ = 2,
+ WNM_DIAGNOSTIC_REPORT = 3,
+ WNM_LOCATION_CFG_REQ = 4,
+ WNM_LOCATION_CFG_RESP = 5,
+ WNM_BSS_TRANS_MGMT_QUERY = 6,
+ WNM_BSS_TRANS_MGMT_REQ = 7,
+ WNM_BSS_TRANS_MGMT_RESP = 8,
+ WNM_FMS_REQ = 9,
+ WNM_FMS_RESP = 10,
+ WNM_COLLOCATED_INTERFERENCE_REQ = 11,
+ WNM_COLLOCATED_INTERFERENCE_REPORT = 12,
+ WNM_TFS_REQ = 13,
+ WNM_TFS_RESP = 14,
+ WNM_TFS_NOTIFY = 15,
+ WNM_SLEEP_MODE_REQ = 16,
+ WNM_SLEEP_MODE_RESP = 17,
+ WNM_TIM_BROADCAST_REQ = 18,
+ WNM_TIM_BROADCAST_RESP = 19,
+ WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20,
+ WNM_CHANNEL_USAGE_REQ = 21,
+ WNM_CHANNEL_USAGE_RESP = 22,
+ WNM_DMS_REQ = 23,
+ WNM_DMS_RESP = 24,
+ WNM_TIMING_MEASUREMENT_REQ = 25,
+ WNM_NOTIFICATION_REQ = 26,
+ WNM_NOTIFICATION_RESP = 27
+};
+
+/* IEEE 802.11v - BSS Transition Management Request - Request Mode */
+#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0)
+#define WNM_BSS_TM_REQ_ABRIDGED BIT(1)
+#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2)
+#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
+#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/version.h b/src/common/version.h
index ba2d2c0..7afba48 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -5,6 +5,6 @@
#define VERSION_STR_POSTFIX ""
#endif /* VERSION_STR_POSTFIX */
-#define VERSION_STR "0.8.x" VERSION_STR_POSTFIX
+#define VERSION_STR "2.0-devel" VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index eb2745e..24a61e4 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -188,6 +188,154 @@ int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
return 0;
}
+
+
+static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
+ struct wpa_ft_ies *parse)
+{
+ const u8 *end, *pos;
+
+ parse->ftie = ie;
+ parse->ftie_len = ie_len;
+
+ pos = ie + sizeof(struct rsn_ftie);
+ end = ie + ie_len;
+
+ while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+ switch (pos[0]) {
+ case FTIE_SUBELEM_R1KH_ID:
+ if (pos[1] != FT_R1KH_ID_LEN) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
+ "length in FTIE: %d", pos[1]);
+ return -1;
+ }
+ parse->r1kh_id = pos + 2;
+ break;
+ case FTIE_SUBELEM_GTK:
+ parse->gtk = pos + 2;
+ parse->gtk_len = pos[1];
+ break;
+ case FTIE_SUBELEM_R0KH_ID:
+ if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
+ "length in FTIE: %d", pos[1]);
+ return -1;
+ }
+ parse->r0kh_id = pos + 2;
+ parse->r0kh_id_len = pos[1];
+ break;
+#ifdef CONFIG_IEEE80211W
+ case FTIE_SUBELEM_IGTK:
+ parse->igtk = pos + 2;
+ parse->igtk_len = pos[1];
+ break;
+#endif /* CONFIG_IEEE80211W */
+ }
+
+ pos += 2 + pos[1];
+ }
+
+ return 0;
+}
+
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
+ struct wpa_ft_ies *parse)
+{
+ const u8 *end, *pos;
+ struct wpa_ie_data data;
+ int ret;
+ const struct rsn_ftie *ftie;
+ int prot_ie_count = 0;
+
+ os_memset(parse, 0, sizeof(*parse));
+ if (ies == NULL)
+ return 0;
+
+ pos = ies;
+ end = ies + ies_len;
+ while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+ switch (pos[0]) {
+ case WLAN_EID_RSN:
+ parse->rsn = pos + 2;
+ parse->rsn_len = pos[1];
+ ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
+ parse->rsn_len + 2,
+ &data);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to parse "
+ "RSN IE: %d", ret);
+ return -1;
+ }
+ if (data.num_pmkid == 1 && data.pmkid)
+ parse->rsn_pmkid = data.pmkid;
+ break;
+ case WLAN_EID_MOBILITY_DOMAIN:
+ parse->mdie = pos + 2;
+ parse->mdie_len = pos[1];
+ break;
+ case WLAN_EID_FAST_BSS_TRANSITION:
+ if (pos[1] < sizeof(*ftie))
+ return -1;
+ ftie = (const struct rsn_ftie *) (pos + 2);
+ prot_ie_count = ftie->mic_control[1];
+ if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
+ return -1;
+ break;
+ case WLAN_EID_TIMEOUT_INTERVAL:
+ parse->tie = pos + 2;
+ parse->tie_len = pos[1];
+ break;
+ case WLAN_EID_RIC_DATA:
+ if (parse->ric == NULL)
+ parse->ric = pos;
+ break;
+ }
+
+ pos += 2 + pos[1];
+ }
+
+ if (prot_ie_count == 0)
+ return 0; /* no MIC */
+
+ /*
+ * Check that the protected IE count matches with IEs included in the
+ * frame.
+ */
+ if (parse->rsn)
+ prot_ie_count--;
+ if (parse->mdie)
+ prot_ie_count--;
+ if (parse->ftie)
+ prot_ie_count--;
+ if (prot_ie_count < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
+ "the protected IE count");
+ return -1;
+ }
+
+ if (prot_ie_count == 0 && parse->ric) {
+ wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
+ "included in protected IE count");
+ return -1;
+ }
+
+ /* Determine the end of the RIC IE(s) */
+ pos = parse->ric;
+ while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
+ prot_ie_count) {
+ prot_ie_count--;
+ pos += 2 + pos[1];
+ }
+ parse->ric_len = pos - parse->ric;
+ if (prot_ie_count) {
+ wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
+ "frame", (int) prot_ie_count);
+ return -1;
+ }
+
+ return 0;
+}
#endif /* CONFIG_IEEE80211R */
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index fe79cee..69437a7 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -358,4 +358,27 @@ int wpa_compare_rsn_ie(int ft_initial_assoc,
const u8 *ie2, size_t ie2len);
int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
+struct wpa_ft_ies {
+ const u8 *mdie;
+ size_t mdie_len;
+ const u8 *ftie;
+ size_t ftie_len;
+ const u8 *r1kh_id;
+ const u8 *gtk;
+ size_t gtk_len;
+ const u8 *r0kh_id;
+ size_t r0kh_id_len;
+ const u8 *rsn;
+ size_t rsn_len;
+ const u8 *rsn_pmkid;
+ const u8 *tie;
+ size_t tie_len;
+ const u8 *igtk;
+ size_t igtk_len;
+ const u8 *ric;
+ size_t ric_len;
+};
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
+
#endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index 88d3a02..3b25f77 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -21,6 +21,7 @@
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef ANDROID
+#include <dirent.h>
#include <cutils/sockets.h>
#include "private/android_filesystem_config.h"
#endif /* ANDROID */
@@ -175,6 +176,56 @@ void wpa_ctrl_close(struct wpa_ctrl *ctrl)
os_free(ctrl);
}
+
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void)
+{
+ DIR *dir;
+ struct dirent entry;
+ struct dirent *result;
+ size_t dirnamelen;
+ int prefixlen = os_strlen(CONFIG_CTRL_IFACE_CLIENT_PREFIX);
+ size_t maxcopy;
+ char pathname[PATH_MAX];
+ char *namep;
+
+ if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
+ return;
+
+ dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
+ CONFIG_CTRL_IFACE_CLIENT_DIR);
+ if (dirnamelen >= sizeof(pathname)) {
+ closedir(dir);
+ return;
+ }
+ namep = pathname + dirnamelen;
+ maxcopy = PATH_MAX - dirnamelen;
+ while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
+ if (os_strncmp(entry.d_name, CONFIG_CTRL_IFACE_CLIENT_PREFIX,
+ prefixlen) == 0) {
+ if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+ unlink(pathname);
+ }
+ }
+ closedir(dir);
+}
+#endif /* ANDROID */
+
+#else /* CONFIG_CTRL_IFACE_UNIX */
+
+#ifdef ANDROID
+void wpa_ctrl_cleanup(void)
+{
+}
+#endif /* ANDROID */
+
#endif /* CONFIG_CTRL_IFACE_UNIX */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 35e5e3d..d13ba02 100644..100755
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -100,10 +100,8 @@ extern "C" {
/** P2P device found */
#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
-#ifdef ANDROID_BRCM_P2P_PATCH
/** P2P device lost */
#define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST "
-#endif
/** A P2P device requested GO negotiation, but we were not ready to start the
* negotiation */
@@ -130,6 +128,10 @@ extern "C" {
#define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
+#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
+
+#define INTERWORKING_AP "INTERWORKING-AP "
+#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
/* hostapd control interface - fixed message prefixes */
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
@@ -267,6 +269,17 @@ int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
*/
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void);
+#endif /* ANDROID */
+
#ifdef CONFIG_CTRL_IFACE_UDP
#define WPA_CTRL_IFACE_PORT 9877
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index 69aa16a..b221dd4 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -12,6 +12,7 @@ include ../lib.rules
CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
#CFLAGS += -DALL_DH_GROUPS
+CFLAGS += -DCONFIG_SHA256
LIB_OBJS= \
aes-cbc.o \
@@ -40,6 +41,7 @@ LIB_OBJS= \
sha1-tlsprf.o \
sha1-tprf.o \
sha256.o \
+ sha256-tlsprf.o \
sha256-internal.o
LIB_OBJS += crypto_internal.o
@@ -48,6 +50,7 @@ LIB_OBJS += crypto_internal-modexp.o
LIB_OBJS += crypto_internal-rsa.o
LIB_OBJS += tls_internal.o
LIB_OBJS += fips_prf_internal.o
+LIB_OBJS += random.o
libcrypto.a: $(LIB_OBJS)
diff --git a/src/crypto/aes-internal-dec.c b/src/crypto/aes-internal-dec.c
index 2d32c03..a0fc45b 100644
--- a/src/crypto/aes-internal-dec.c
+++ b/src/crypto/aes-internal-dec.c
@@ -32,7 +32,7 @@
*
* @return the number of rounds for the given cipher key size.
*/
-void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
+static void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
{
int Nr = 10, i, j;
u32 temp;
diff --git a/src/crypto/aes-internal-enc.c b/src/crypto/aes-internal-enc.c
index 2f19826..8726aa7 100644
--- a/src/crypto/aes-internal-enc.c
+++ b/src/crypto/aes-internal-enc.c
@@ -27,7 +27,7 @@
#include "crypto.h"
#include "aes_i.h"
-void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
+static void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
{
u32 s0, s1, s2, s3, t0, t1, t2, t3;
const int Nr = 10;
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 587b5a9..6dca191 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -155,7 +155,8 @@ void aes_decrypt_deinit(void *ctx);
enum crypto_hash_alg {
CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
- CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1
+ CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,
+ CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
};
struct crypto_hash;
diff --git a/src/crypto/crypto_internal-rsa.c b/src/crypto/crypto_internal-rsa.c
index 205042c..7f0a5cf 100644
--- a/src/crypto/crypto_internal-rsa.c
+++ b/src/crypto/crypto_internal-rsa.c
@@ -17,7 +17,6 @@
#include "common.h"
#include "crypto.h"
#include "tls/rsa.h"
-#include "tls/bignum.h"
#include "tls/pkcs1.h"
#include "tls/pkcs8.h"
diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c
index 8fdba65..9362fe1 100644
--- a/src/crypto/crypto_internal.c
+++ b/src/crypto/crypto_internal.c
@@ -1,6 +1,6 @@
/*
* Crypto wrapper for internal crypto implementation
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,6 +16,7 @@
#include "common.h"
#include "crypto.h"
+#include "sha256_i.h"
#include "sha1_i.h"
#include "md5_i.h"
@@ -24,6 +25,9 @@ struct crypto_hash {
union {
struct MD5Context md5;
struct SHA1Context sha1;
+#ifdef CONFIG_SHA256
+ struct sha256_state sha256;
+#endif /* CONFIG_SHA256 */
} u;
u8 key[64];
size_t key_len;
@@ -35,7 +39,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
{
struct crypto_hash *ctx;
u8 k_pad[64];
- u8 tk[20];
+ u8 tk[32];
size_t i;
ctx = os_zalloc(sizeof(*ctx));
@@ -51,6 +55,11 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
case CRYPTO_HASH_ALG_SHA1:
SHA1Init(&ctx->u.sha1);
break;
+#ifdef CONFIG_SHA256
+ case CRYPTO_HASH_ALG_SHA256:
+ sha256_init(&ctx->u.sha256);
+ break;
+#endif /* CONFIG_SHA256 */
case CRYPTO_HASH_ALG_HMAC_MD5:
if (key_len > sizeof(k_pad)) {
MD5Init(&ctx->u.md5);
@@ -63,7 +72,8 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
ctx->key_len = key_len;
os_memcpy(k_pad, key, key_len);
- os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+ if (key_len < sizeof(k_pad))
+ os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
for (i = 0; i < sizeof(k_pad); i++)
k_pad[i] ^= 0x36;
MD5Init(&ctx->u.md5);
@@ -81,12 +91,34 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
ctx->key_len = key_len;
os_memcpy(k_pad, key, key_len);
- os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+ if (key_len < sizeof(k_pad))
+ os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
for (i = 0; i < sizeof(k_pad); i++)
k_pad[i] ^= 0x36;
SHA1Init(&ctx->u.sha1);
SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
break;
+#ifdef CONFIG_SHA256
+ case CRYPTO_HASH_ALG_HMAC_SHA256:
+ if (key_len > sizeof(k_pad)) {
+ sha256_init(&ctx->u.sha256);
+ sha256_process(&ctx->u.sha256, key, key_len);
+ sha256_done(&ctx->u.sha256, tk);
+ key = tk;
+ key_len = 32;
+ }
+ os_memcpy(ctx->key, key, key_len);
+ ctx->key_len = key_len;
+
+ os_memcpy(k_pad, key, key_len);
+ if (key_len < sizeof(k_pad))
+ os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+ for (i = 0; i < sizeof(k_pad); i++)
+ k_pad[i] ^= 0x36;
+ sha256_init(&ctx->u.sha256);
+ sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+ break;
+#endif /* CONFIG_SHA256 */
default:
os_free(ctx);
return NULL;
@@ -110,6 +142,14 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
case CRYPTO_HASH_ALG_HMAC_SHA1:
SHA1Update(&ctx->u.sha1, data, len);
break;
+#ifdef CONFIG_SHA256
+ case CRYPTO_HASH_ALG_SHA256:
+ case CRYPTO_HASH_ALG_HMAC_SHA256:
+ sha256_process(&ctx->u.sha256, data, len);
+ break;
+#endif /* CONFIG_SHA256 */
+ default:
+ break;
}
}
@@ -146,6 +186,17 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
*len = 20;
SHA1Final(mac, &ctx->u.sha1);
break;
+#ifdef CONFIG_SHA256
+ case CRYPTO_HASH_ALG_SHA256:
+ if (*len < 32) {
+ *len = 32;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 32;
+ sha256_done(&ctx->u.sha256, mac);
+ break;
+#endif /* CONFIG_SHA256 */
case CRYPTO_HASH_ALG_HMAC_MD5:
if (*len < 16) {
*len = 16;
@@ -186,6 +237,31 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
SHA1Update(&ctx->u.sha1, mac, 20);
SHA1Final(mac, &ctx->u.sha1);
break;
+#ifdef CONFIG_SHA256
+ case CRYPTO_HASH_ALG_HMAC_SHA256:
+ if (*len < 32) {
+ *len = 32;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 32;
+
+ sha256_done(&ctx->u.sha256, mac);
+
+ os_memcpy(k_pad, ctx->key, ctx->key_len);
+ os_memset(k_pad + ctx->key_len, 0,
+ sizeof(k_pad) - ctx->key_len);
+ for (i = 0; i < sizeof(k_pad); i++)
+ k_pad[i] ^= 0x5c;
+ sha256_init(&ctx->u.sha256);
+ sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+ sha256_process(&ctx->u.sha256, mac, 32);
+ sha256_done(&ctx->u.sha256, mac);
+ break;
+#endif /* CONFIG_SHA256 */
+ default:
+ os_free(ctx);
+ return -1;
}
os_free(ctx);
diff --git a/src/crypto/dh_group5.c b/src/crypto/dh_group5.c
index 8c475bf..2a67d99 100644
--- a/src/crypto/dh_group5.c
+++ b/src/crypto/dh_group5.c
@@ -22,7 +22,7 @@
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
*publ = dh_init(dh_groups_get(5), priv);
- if (*publ == 0)
+ if (*publ == NULL)
return NULL;
return (void *) 1;
}
diff --git a/src/crypto/fips_prf_internal.c b/src/crypto/fips_prf_internal.c
index a85cb14..1e0c453 100644
--- a/src/crypto/fips_prf_internal.c
+++ b/src/crypto/fips_prf_internal.c
@@ -28,13 +28,14 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
u8 *xpos = x;
u32 carry;
- if (seed_len > sizeof(xkey))
+ if (seed_len < sizeof(xkey))
+ os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+ else
seed_len = sizeof(xkey);
/* FIPS 186-2 + change notice 1 */
os_memcpy(xkey, seed, seed_len);
- os_memset(xkey + seed_len, 0, 64 - seed_len);
t[0] = 0x67452301;
t[1] = 0xEFCDAB89;
t[2] = 0x98BADCFE;
diff --git a/src/crypto/md5-internal.c b/src/crypto/md5-internal.c
index f8692a9..137ad91 100644
--- a/src/crypto/md5-internal.c
+++ b/src/crypto/md5-internal.c
@@ -188,7 +188,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
MD5Transform(ctx->buf, (u32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
os_memcpy(digest, ctx->buf, 16);
- os_memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+ os_memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c
index dae15ab..c439ae9 100644
--- a/src/crypto/ms_funcs.c
+++ b/src/crypto/ms_funcs.c
@@ -19,6 +19,60 @@
#include "ms_funcs.h"
#include "crypto.h"
+/**
+ * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
+ * @utf8_string: UTF-8 string (IN)
+ * @utf8_string_len: Length of utf8_string (IN)
+ * @ucs2_buffer: UCS-2 buffer (OUT)
+ * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
+ * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
+ * Returns: 0 on success, -1 on failure
+ */
+static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
+ u8 *ucs2_buffer, size_t ucs2_buffer_size,
+ size_t *ucs2_string_size)
+{
+ size_t i, j;
+
+ for (i = 0, j = 0; i < utf8_string_len; i++) {
+ u8 c = utf8_string[i];
+ if (j >= ucs2_buffer_size) {
+ /* input too long */
+ return -1;
+ }
+ if (c <= 0x7F) {
+ WPA_PUT_LE16(ucs2_buffer + j, c);
+ j += 2;
+ } else if (i == utf8_string_len - 1 ||
+ j >= ucs2_buffer_size - 1) {
+ /* incomplete surrogate */
+ return -1;
+ } else {
+ u8 c2 = utf8_string[++i];
+ if ((c & 0xE0) == 0xC0) {
+ /* two-byte encoding */
+ WPA_PUT_LE16(ucs2_buffer + j,
+ ((c & 0x1F) << 6) | (c2 & 0x3F));
+ j += 2;
+ } else if (i == utf8_string_len ||
+ j >= ucs2_buffer_size - 1) {
+ /* incomplete surrogate */
+ return -1;
+ } else {
+ /* three-byte encoding */
+ u8 c3 = utf8_string[++i];
+ WPA_PUT_LE16(ucs2_buffer + j,
+ ((c & 0xF) << 12) |
+ ((c2 & 0x3F) << 6) | (c3 & 0x3F));
+ }
+ }
+ }
+
+ if (ucs2_string_size)
+ *ucs2_string_size = j / 2;
+ return 0;
+}
+
/**
* challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
@@ -53,7 +107,7 @@ static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
/**
* nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
* @password_len: Length of password
* @password_hash: 16-octet PasswordHash (OUT)
* Returns: 0 on success, -1 on failure
@@ -62,18 +116,13 @@ int nt_password_hash(const u8 *password, size_t password_len,
u8 *password_hash)
{
u8 buf[512], *pos;
- size_t i, len;
+ size_t len, max_len;
- if (password_len > 256)
- password_len = 256;
-
- /* Convert password into unicode */
- for (i = 0; i < password_len; i++) {
- buf[2 * i] = password[i];
- buf[2 * i + 1] = 0;
- }
+ max_len = sizeof(buf);
+ if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
+ return -1;
- len = password_len * 2;
+ len *= 2;
pos = buf;
return md4_vector(1, (const u8 **) &pos, &len, password_hash);
}
@@ -117,7 +166,7 @@ void challenge_response(const u8 *challenge, const u8 *password_hash,
* @peer_challenge: 16-octet PeerChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
* @password_len: Length of password
* @response: 24-octet Response (OUT)
* Returns: 0 on success, -1 on failure
@@ -225,7 +274,7 @@ int generate_authenticator_response_pwhash(
/**
* generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
* @password_len: Length of password
* @nt_response: 24-octet NT-Response (IN)
* @peer_challenge: 16-octet PeerChallenge (IN)
@@ -254,7 +303,7 @@ int generate_authenticator_response(const u8 *password, size_t password_len,
/**
* nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
* @challenge: 8-octet Challenge (IN)
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
* @password_len: Length of password
* @response: 24-octet Response (OUT)
* Returns: 0 on success, -1 on failure
@@ -375,7 +424,7 @@ int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
/**
* encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
* @password_len: Length of password
* @password_hash: 16-octet PasswordHash (IN)
* @pw_block: 516-byte PwBlock (OUT)
@@ -385,18 +434,23 @@ int encrypt_pw_block_with_password_hash(
const u8 *password, size_t password_len,
const u8 *password_hash, u8 *pw_block)
{
- size_t i, offset;
+ size_t ucs2_len, offset;
u8 *pos;
- if (password_len > 256)
+ os_memset(pw_block, 0, PWBLOCK_LEN);
+
+ if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
return -1;
- os_memset(pw_block, 0, PWBLOCK_LEN);
- offset = (256 - password_len) * 2;
- if (os_get_random(pw_block, offset) < 0)
+ if (ucs2_len > 256)
return -1;
- for (i = 0; i < password_len; i++)
- pw_block[offset + i * 2] = password[i];
+
+ offset = (256 - ucs2_len) * 2;
+ if (offset != 0) {
+ os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
+ if (os_get_random(pw_block, offset) < 0)
+ return -1;
+ }
/*
* PasswordLength is 4 octets, but since the maximum password length is
* 256, only first two (in little endian byte order) can be non-zero.
@@ -410,9 +464,9 @@ int encrypt_pw_block_with_password_hash(
/**
* new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
- * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
* @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
* @old_password_len: Length of old_password
* @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
* Returns: 0 on success, -1 on failure
@@ -450,9 +504,9 @@ void nt_password_hash_encrypted_with_block(const u8 *password_hash,
/**
* old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
- * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
* @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
* @old_password_len: Length of old_password
* @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
* Returns: 0 on success, -1 on failure
diff --git a/src/crypto/random.c b/src/crypto/random.c
index f545917..a54e197 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -354,23 +354,31 @@ static void random_write_entropy(void)
char buf[RANDOM_ENTROPY_SIZE];
FILE *f;
u8 opr;
+ int fail = 0;
if (!random_entropy_file)
return;
- random_get_bytes(buf, RANDOM_ENTROPY_SIZE);
+ if (random_get_bytes(buf, RANDOM_ENTROPY_SIZE) < 0)
+ return;
f = fopen(random_entropy_file, "wb");
if (f == NULL) {
- wpa_printf(MSG_ERROR, "random: Could not write %s",
- random_entropy_file);
+ wpa_printf(MSG_ERROR, "random: Could not open entropy file %s "
+ "for writing", random_entropy_file);
return;
}
opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
- fwrite(&opr, 1, 1, f);
- fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f);
+ if (fwrite(&opr, 1, 1, f) != 1 ||
+ fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f) != 1)
+ fail = 1;
fclose(f);
+ if (fail) {
+ wpa_printf(MSG_ERROR, "random: Could not write entropy data "
+ "to %s", random_entropy_file);
+ return;
+ }
wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
"(own_pool_ready=%u)",
diff --git a/src/crypto/sha1-pbkdf2.c b/src/crypto/sha1-pbkdf2.c
index 11323de..9dac977 100644
--- a/src/crypto/sha1-pbkdf2.c
+++ b/src/crypto/sha1-pbkdf2.c
@@ -16,8 +16,6 @@
#include "common.h"
#include "sha1.h"
-#include "md5.h"
-#include "crypto.h"
static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
size_t ssid_len, int iterations, unsigned int count,
diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c
index 2c8c029..f98fd65 100644
--- a/src/crypto/sha1-tlsprf.c
+++ b/src/crypto/sha1-tlsprf.c
@@ -17,11 +17,10 @@
#include "common.h"
#include "sha1.h"
#include "md5.h"
-#include "crypto.h"
/**
- * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
+ * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
* @secret: Key for PRF
* @secret_len: Length of the key in bytes
* @label: A unique label for each purpose of the PRF
@@ -34,8 +33,8 @@
* This function is used to derive new, cryptographically separate keys from a
* given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
*/
-int tls_prf(const u8 *secret, size_t secret_len, const char *label,
- const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
+ const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
{
size_t L_S1, L_S2, i;
const u8 *S1, *S2;
diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h
index c1a6233..f0c1a5f 100644
--- a/src/crypto/sha1.h
+++ b/src/crypto/sha1.h
@@ -25,9 +25,9 @@ int sha1_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len);
-int __must_check tls_prf(const u8 *secret, size_t secret_len,
- const char *label, const u8 *seed, size_t seed_len,
- u8 *out, size_t outlen);
+int __must_check tls_prf_sha1_md5(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed,
+ size_t seed_len, u8 *out, size_t outlen);
int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen);
#endif /* SHA1_H */
diff --git a/src/crypto/sha256-internal.c b/src/crypto/sha256-internal.c
index b061373..ef5751d 100644
--- a/src/crypto/sha256-internal.c
+++ b/src/crypto/sha256-internal.c
@@ -1,6 +1,6 @@
/*
* SHA-256 hash implementation and interface functions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,19 +16,9 @@
#include "common.h"
#include "sha256.h"
+#include "sha256_i.h"
#include "crypto.h"
-struct sha256_state {
- u64 length;
- u32 state[8], curlen;
- u8 buf[64];
-};
-
-static void sha256_init(struct sha256_state *md);
-static int sha256_process(struct sha256_state *md, const unsigned char *in,
- unsigned long inlen);
-static int sha256_done(struct sha256_state *md, unsigned char *out);
-
/**
* sha256_vector - SHA256 hash for data vector
@@ -137,7 +127,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf)
/* Initialize the hash state */
-static void sha256_init(struct sha256_state *md)
+void sha256_init(struct sha256_state *md)
{
md->curlen = 0;
md->length = 0;
@@ -158,32 +148,31 @@ static void sha256_init(struct sha256_state *md)
@param inlen The length of the data (octets)
@return CRYPT_OK if successful
*/
-static int sha256_process(struct sha256_state *md, const unsigned char *in,
- unsigned long inlen)
+int sha256_process(struct sha256_state *md, const unsigned char *in,
+ unsigned long inlen)
{
unsigned long n;
-#define block_size 64
- if (md->curlen > sizeof(md->buf))
+ if (md->curlen >= sizeof(md->buf))
return -1;
while (inlen > 0) {
- if (md->curlen == 0 && inlen >= block_size) {
+ if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) {
if (sha256_compress(md, (unsigned char *) in) < 0)
return -1;
- md->length += block_size * 8;
- in += block_size;
- inlen -= block_size;
+ md->length += SHA256_BLOCK_SIZE * 8;
+ in += SHA256_BLOCK_SIZE;
+ inlen -= SHA256_BLOCK_SIZE;
} else {
- n = MIN(inlen, (block_size - md->curlen));
+ n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen));
os_memcpy(md->buf + md->curlen, in, n);
md->curlen += n;
in += n;
inlen -= n;
- if (md->curlen == block_size) {
+ if (md->curlen == SHA256_BLOCK_SIZE) {
if (sha256_compress(md, md->buf) < 0)
return -1;
- md->length += 8 * block_size;
+ md->length += 8 * SHA256_BLOCK_SIZE;
md->curlen = 0;
}
}
@@ -199,7 +188,7 @@ static int sha256_process(struct sha256_state *md, const unsigned char *in,
@param out [out] The destination of the hash (32 bytes)
@return CRYPT_OK if successful
*/
-static int sha256_done(struct sha256_state *md, unsigned char *out)
+int sha256_done(struct sha256_state *md, unsigned char *out)
{
int i;
@@ -217,14 +206,14 @@ static int sha256_done(struct sha256_state *md, unsigned char *out)
* encoding like normal.
*/
if (md->curlen > 56) {
- while (md->curlen < 64) {
+ while (md->curlen < SHA256_BLOCK_SIZE) {
md->buf[md->curlen++] = (unsigned char) 0;
}
sha256_compress(md, md->buf);
md->curlen = 0;
}
- /* pad upto 56 bytes of zeroes */
+ /* pad up to 56 bytes of zeroes */
while (md->curlen < 56) {
md->buf[md->curlen++] = (unsigned char) 0;
}
diff --git a/src/crypto/sha256-tlsprf.c b/src/crypto/sha256-tlsprf.c
new file mode 100644
index 0000000..6763c96
--- /dev/null
+++ b/src/crypto/sha256-tlsprf.c
@@ -0,0 +1,72 @@
+/*
+ * TLS PRF P_SHA256
+ * Copyright (c) 2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+
+
+/**
+ * tls_prf_sha256 - Pseudo-Random Function for TLS v1.2 (P_SHA256, RFC 5246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
+ */
+void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
+ const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+ size_t clen;
+ u8 A[SHA256_MAC_LEN];
+ u8 P[SHA256_MAC_LEN];
+ size_t pos;
+ const unsigned char *addr[3];
+ size_t len[3];
+
+ addr[0] = A;
+ len[0] = SHA256_MAC_LEN;
+ addr[1] = (unsigned char *) label;
+ len[1] = os_strlen(label);
+ addr[2] = seed;
+ len[2] = seed_len;
+
+ /*
+ * RFC 5246, Chapter 5
+ * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+ * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+ * PRF(secret, label, seed) = P_SHA256(secret, label + seed)
+ */
+
+ hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A);
+
+ pos = 0;
+ while (pos < outlen) {
+ hmac_sha256_vector(secret, secret_len, 3, addr, len, P);
+ hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A);
+
+ clen = outlen - pos;
+ if (clen > SHA256_MAC_LEN)
+ clen = SHA256_MAC_LEN;
+ os_memcpy(out + pos, P, clen);
+ pos += clen;
+ }
+}
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index dc597f0..b1ce6af 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -1,6 +1,6 @@
/*
* SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,5 +23,8 @@ void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+void tls_prf_sha256(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
#endif /* SHA256_H */
diff --git a/src/crypto/sha256_i.h b/src/crypto/sha256_i.h
new file mode 100644
index 0000000..20ae488
--- /dev/null
+++ b/src/crypto/sha256_i.h
@@ -0,0 +1,31 @@
+/*
+ * SHA-256 internal definitions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef SHA256_I_H
+#define SHA256_I_H
+
+#define SHA256_BLOCK_SIZE 64
+
+struct sha256_state {
+ u64 length;
+ u32 state[8], curlen;
+ u8 buf[SHA256_BLOCK_SIZE];
+};
+
+void sha256_init(struct sha256_state *md);
+int sha256_process(struct sha256_state *md, const unsigned char *in,
+ unsigned long inlen);
+int sha256_done(struct sha256_state *md, unsigned char *out);
+
+#endif /* SHA256_I_H */
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 0928b5b..d9d88cb 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -24,8 +24,6 @@ struct tls_keys {
size_t client_random_len;
const u8 *server_random;
size_t server_random_len;
- const u8 *inner_secret; /* TLS/IA inner secret */
- size_t inner_secret_len;
};
enum tls_event {
@@ -72,6 +70,7 @@ struct tls_config {
const char *pkcs11_engine_path;
const char *pkcs11_module_path;
int fips_mode;
+ int cert_in_cb;
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
@@ -114,7 +113,6 @@ struct tls_config {
* specific for now)
* @cert_id: the certificate's id when using engine
* @ca_cert_id: the CA certificate's id when using engine
- * @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
* @flags: Parameter options (TLS_CONN_*)
*
* TLS connection parameters to be configured with tls_connection_set_params()
@@ -142,7 +140,6 @@ struct tls_connection_params {
const char *dh_file;
const u8 *dh_blob;
size_t dh_blob_len;
- int tls_ia;
/* OpenSSL specific variables */
int engine;
@@ -282,20 +279,6 @@ int __must_check tls_connection_set_verify(void *tls_ctx,
int verify_peer);
/**
- * tls_connection_set_ia - Set TLS/IA parameters
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @tls_ia: 1 = enable TLS/IA
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to configure TLS/IA in server mode where
- * tls_connection_set_params() is not used.
- */
-int __must_check tls_connection_set_ia(void *tls_ctx,
- struct tls_connection *conn,
- int tls_ia);
-
-/**
* tls_connection_get_keys - Get master key and random data from TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
@@ -322,7 +305,7 @@ int __must_check tls_connection_get_keys(void *tls_ctx,
* not exported from the TLS library, tls_connection_prf() is required so that
* further keying material can be derived from the master secret. If not
* implemented, the function will still need to be defined, but it can just
- * return -1. Example implementation of this function is in tls_prf() function
+ * return -1. Example implementation of this function is in tls_prf_sha1_md5()
* when it is called with seed set to client_random|server_random (or
* server_random|client_random).
*/
@@ -364,6 +347,12 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
const struct wpabuf *in_data,
struct wpabuf **appl_data);
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ struct wpabuf **appl_data,
+ int *more_data_needed);
+
/**
* tls_connection_server_handshake - Process TLS handshake (server side)
* @tls_ctx: TLS context data from tls_init()
@@ -409,6 +398,11 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data);
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ int *more_data_needed);
+
/**
* tls_connection_resumed - Was session resumption used
* @tls_ctx: TLS context data from tls_init()
@@ -514,7 +508,6 @@ int tls_connection_get_write_alerts(void *tls_ctx,
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn);
-#define TLS_CAPABILITY_IA 0x0001 /* TLS Inner Application (TLS/IA) */
/**
* tls_capabilities - Get supported TLS capabilities
* @tls_ctx: TLS context data from tls_init()
@@ -522,42 +515,6 @@ int tls_connection_get_keyblock_size(void *tls_ctx,
*/
unsigned int tls_capabilities(void *tls_ctx);
-/**
- * tls_connection_ia_send_phase_finished - Send a TLS/IA PhaseFinished message
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished
- * Returns: Encrypted TLS/IA data, %NULL on failure
- *
- * This function is used to send the TLS/IA end phase message, e.g., when the
- * EAP server completes EAP-TTLSv1.
- */
-struct wpabuf * tls_connection_ia_send_phase_finished(
- void *tls_ctx, struct tls_connection *conn, int final);
-
-/**
- * tls_connection_ia_final_phase_finished - Has final phase been completed
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * Returns: 1 if valid FinalPhaseFinished has been received, 0 if not, or -1
- * on failure
- */
-int __must_check tls_connection_ia_final_phase_finished(
- void *tls_ctx, struct tls_connection *conn);
-
-/**
- * tls_connection_ia_permute_inner_secret - Permute TLS/IA inner secret
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @key: Session key material (session_key vectors with 2-octet length), or
- * %NULL if no session key was generating in the current phase
- * @key_len: Length of session key material
- * Returns: 0 on success, -1 on failure
- */
-int __must_check tls_connection_ia_permute_inner_secret(
- void *tls_ctx, struct tls_connection *conn,
- const u8 *key, size_t key_len);
-
typedef int (*tls_session_ticket_cb)
(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
const u8 *server_random, u8 *master_secret);
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index c3a7358..afa5268 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -1,6 +1,6 @@
/*
* SSL/TLS interface functions for GnuTLS
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,28 +19,12 @@
#include <gnutls/pkcs12.h>
#endif /* PKCS12_FUNCS */
-#ifdef CONFIG_GNUTLS_EXTRA
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
-#define GNUTLS_IA
-#include <gnutls/extra.h>
-#if LIBGNUTLS_VERSION_NUMBER == 0x010302
-/* This function is not included in the current gnutls/extra.h even though it
- * should be, so define it here as a workaround for the time being. */
-int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
-#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
-#endif /* CONFIG_GNUTLS_EXTRA */
-
#include "common.h"
#include "tls.h"
-#ifndef TLS_RANDOM_SIZE
-#define TLS_RANDOM_SIZE 32
-#endif
-#ifndef TLS_MASTER_SIZE
-#define TLS_MASTER_SIZE 48
-#endif
+#define WPA_TLS_RANDOM_SIZE 32
+#define WPA_TLS_MASTER_SIZE 48
#if LIBGNUTLS_VERSION_NUMBER < 0x010302
@@ -77,9 +61,9 @@ typedef struct {
gnutls_mac_algorithm_t write_mac_algorithm;
gnutls_compression_method_t write_compression_algorithm;
cipher_suite_st current_cipher_suite;
- opaque master_secret[TLS_MASTER_SIZE];
- opaque client_random[TLS_RANDOM_SIZE];
- opaque server_random[TLS_RANDOM_SIZE];
+ opaque master_secret[WPA_TLS_MASTER_SIZE];
+ opaque client_random[WPA_TLS_RANDOM_SIZE];
+ opaque server_random[WPA_TLS_RANDOM_SIZE];
/* followed by stuff we are not interested in */
} security_parameters_st;
@@ -118,21 +102,6 @@ struct tls_connection {
int params_set;
gnutls_certificate_credentials_t xcred;
-
- int tls_ia;
- int final_phase_finished;
-
-#ifdef GNUTLS_IA
- gnutls_ia_server_credentials_t iacred_srv;
- gnutls_ia_client_credentials_t iacred_cli;
-
- /* Session keys generated in the current phase for inner secret
- * permutation before generating/verifying PhaseFinished. */
- u8 *session_keys;
- size_t session_keys_len;
-
- u8 inner_secret[TLS_MASTER_SIZE];
-#endif /* GNUTLS_IA */
};
@@ -285,8 +254,12 @@ static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
static int tls_gnutls_init_session(struct tls_global *global,
struct tls_connection *conn)
{
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+ const char *err;
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
const int protos[2] = { GNUTLS_TLS1, 0 };
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
int ret;
ret = gnutls_init(&conn->session,
@@ -301,6 +274,15 @@ static int tls_gnutls_init_session(struct tls_global *global,
if (ret < 0)
goto fail;
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+ ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
+ &err);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
+ "'%s'", err);
+ goto fail;
+ }
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
if (ret < 0)
goto fail;
@@ -308,6 +290,7 @@ static int tls_gnutls_init_session(struct tls_global *global,
ret = gnutls_protocol_set_priority(conn->session, protos);
if (ret < 0)
goto fail;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
gnutls_transport_set_pull_function(conn->session, tls_pull_func);
gnutls_transport_set_push_function(conn->session, tls_push_func);
@@ -364,17 +347,6 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
if (conn == NULL)
return;
-#ifdef GNUTLS_IA
- if (conn->iacred_srv)
- gnutls_ia_free_server_credentials(conn->iacred_srv);
- if (conn->iacred_cli)
- gnutls_ia_free_client_credentials(conn->iacred_cli);
- if (conn->session_keys) {
- os_memset(conn->session_keys, 0, conn->session_keys_len);
- os_free(conn->session_keys);
- }
-#endif /* GNUTLS_IA */
-
gnutls_certificate_free_credentials(conn->xcred);
gnutls_deinit(conn->session);
os_free(conn->pre_shared_secret);
@@ -407,14 +379,6 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
wpabuf_free(conn->push_buf);
conn->push_buf = NULL;
conn->established = 0;
- conn->final_phase_finished = 0;
-#ifdef GNUTLS_IA
- if (conn->session_keys) {
- os_memset(conn->session_keys, 0, conn->session_keys_len);
- os_free(conn->session_keys);
- }
- conn->session_keys_len = 0;
-#endif /* GNUTLS_IA */
gnutls_deinit(conn->session);
if (tls_gnutls_init_session(global, conn)) {
@@ -597,11 +561,13 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
}
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
gnutls_certificate_set_verify_flags(
conn->xcred,
GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
}
if (params->client_cert && params->private_key) {
@@ -646,7 +612,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
}
- conn->tls_ia = params->tls_ia;
conn->params_set = 1;
ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
@@ -656,28 +621,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
gnutls_strerror(ret));
}
-#ifdef GNUTLS_IA
- if (conn->iacred_cli)
- gnutls_ia_free_client_credentials(conn->iacred_cli);
-
- ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
- if (ret) {
- wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
- gnutls_strerror(ret));
- return -1;
- }
-
- ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
- conn->iacred_cli);
- if (ret) {
- wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
- gnutls_strerror(ret));
- gnutls_ia_free_client_credentials(conn->iacred_cli);
- conn->iacred_cli = NULL;
- return -1;
- }
-#endif /* GNUTLS_IE */
-
return ret;
}
@@ -729,11 +672,13 @@ int tls_global_set_params(void *tls_ctx,
GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
}
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
gnutls_certificate_set_verify_flags(
global->xcred,
GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
}
if (params->client_cert && params->private_key) {
@@ -822,10 +767,11 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
os_memset(keys, 0, sizeof(*keys));
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
sec = &conn->session->security_parameters;
keys->master_key = sec->master_secret;
- keys->master_key_len = TLS_MASTER_SIZE;
+ keys->master_key_len = WPA_TLS_MASTER_SIZE;
keys->client_random = sec->client_random;
keys->server_random = sec->server_random;
#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
@@ -835,16 +781,12 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
(u8 *) gnutls_session_get_server_random(conn->session);
/* No access to master_secret */
#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
-#ifdef GNUTLS_IA
- gnutls_ia_extract_inner_secret(conn->session,
- (char *) conn->inner_secret);
- keys->inner_secret = conn->inner_secret;
- keys->inner_secret_len = TLS_MASTER_SIZE;
-#endif /* GNUTLS_IA */
-
- keys->client_random_len = TLS_RANDOM_SIZE;
- keys->server_random_len = TLS_RANDOM_SIZE;
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
+ keys->client_random_len = WPA_TLS_RANDOM_SIZE;
+ keys->server_random_len = WPA_TLS_RANDOM_SIZE;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
return 0;
}
@@ -883,11 +825,13 @@ static int tls_connection_verify_peer(struct tls_connection *conn,
if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
+ *err = GNUTLS_A_INTERNAL_ERROR;
if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
"algorithm");
*err = GNUTLS_A_INSUFFICIENT_SECURITY;
}
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
if (status & GNUTLS_CERT_NOT_ACTIVATED) {
wpa_printf(MSG_INFO, "TLS: Certificate not yet "
"activated");
@@ -897,6 +841,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn,
wpa_printf(MSG_INFO, "TLS: Certificate expired");
*err = GNUTLS_A_CERTIFICATE_EXPIRED;
}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
return -1;
}
@@ -988,7 +933,7 @@ static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
wpabuf_size(ad));
wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
if (res < 0) {
- wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
+ wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
"(%s)", __func__, (int) res,
gnutls_strerror(res));
wpabuf_free(ad);
@@ -1062,20 +1007,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
goto out;
}
-#ifdef CONFIG_GNUTLS_EXTRA
- if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
- wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
- conn->failed++;
- return NULL;
- }
-#endif /* CONFIG_GNUTLS_EXTRA */
-
- if (conn->tls_ia)
- wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
- else {
- wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
- "successfully");
- }
+ wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
conn->established = 1;
if (conn->push_buf == NULL) {
/* Need to return something to get final TLS ACK. */
@@ -1122,12 +1054,6 @@ struct wpabuf * tls_connection_encrypt(void *tls_ctx,
ssize_t res;
struct wpabuf *buf;
-#ifdef GNUTLS_IA
- if (conn->tls_ia)
- res = gnutls_ia_send(conn->session, wpabuf_head(in_data),
- wpabuf_len(in_data));
- else
-#endif /* GNUTLS_IA */
res = gnutls_record_send(conn->session, wpabuf_head(in_data),
wpabuf_len(in_data));
if (res < 0) {
@@ -1170,65 +1096,6 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
if (out == NULL)
return NULL;
-#ifdef GNUTLS_IA
- if (conn->tls_ia) {
- res = gnutls_ia_recv(conn->session, wpabuf_mhead(out),
- wpabuf_size(out));
- if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
- res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) {
- int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
- wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
- __func__, final ? "Final" : "Intermediate");
-
- res = gnutls_ia_permute_inner_secret(
- conn->session, conn->session_keys_len,
- (char *) conn->session_keys);
- if (conn->session_keys) {
- os_memset(conn->session_keys, 0,
- conn->session_keys_len);
- os_free(conn->session_keys);
- }
- conn->session_keys = NULL;
- conn->session_keys_len = 0;
- if (res) {
- wpa_printf(MSG_DEBUG, "%s: Failed to permute "
- "inner secret: %s",
- __func__, gnutls_strerror(res));
- wpabuf_free(out);
- return NULL;
- }
-
- res = gnutls_ia_verify_endphase(conn->session,
- wpabuf_head(out));
- if (res == 0) {
- wpa_printf(MSG_DEBUG, "%s: Correct endphase "
- "checksum", __func__);
- } else {
- wpa_printf(MSG_INFO, "%s: Endphase "
- "verification failed: %s",
- __func__, gnutls_strerror(res));
- wpabuf_free(out);
- return NULL;
- }
-
- if (final)
- conn->final_phase_finished = 1;
-
- return out;
- }
-
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
- "(%s)", __func__, (int) res,
- gnutls_strerror(res));
- wpabuf_free(out);
- return NULL;
- }
- wpabuf_put(out, res);
- return out;
- }
-#endif /* GNUTLS_IA */
-
res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
wpabuf_size(out));
if (res < 0) {
@@ -1319,133 +1186,7 @@ int tls_connection_get_keyblock_size(void *tls_ctx,
unsigned int tls_capabilities(void *tls_ctx)
{
- unsigned int capa = 0;
-
-#ifdef GNUTLS_IA
- capa |= TLS_CAPABILITY_IA;
-#endif /* GNUTLS_IA */
-
- return capa;
-}
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
- int tls_ia)
-{
-#ifdef GNUTLS_IA
- int ret;
-
- if (conn == NULL)
- return -1;
-
- conn->tls_ia = tls_ia;
- if (!tls_ia)
- return 0;
-
- ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
- if (ret) {
- wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
- gnutls_strerror(ret));
- return -1;
- }
-
- ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
- conn->iacred_srv);
- if (ret) {
- wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
- gnutls_strerror(ret));
- gnutls_ia_free_server_credentials(conn->iacred_srv);
- conn->iacred_srv = NULL;
- return -1;
- }
-
- return 0;
-#else /* GNUTLS_IA */
- return -1;
-#endif /* GNUTLS_IA */
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
- void *tls_ctx, struct tls_connection *conn, int final)
-{
-#ifdef GNUTLS_IA
- int ret;
- struct wpabuf *buf;
-
- if (conn == NULL || conn->session == NULL || !conn->tls_ia)
- return NULL;
-
- ret = gnutls_ia_permute_inner_secret(conn->session,
- conn->session_keys_len,
- (char *) conn->session_keys);
- if (conn->session_keys) {
- os_memset(conn->session_keys, 0, conn->session_keys_len);
- os_free(conn->session_keys);
- }
- conn->session_keys = NULL;
- conn->session_keys_len = 0;
- if (ret) {
- wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
- __func__, gnutls_strerror(ret));
- return NULL;
- }
-
- ret = gnutls_ia_endphase_send(conn->session, final);
- if (ret) {
- wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
- __func__, gnutls_strerror(ret));
- return NULL;
- }
-
- buf = conn->push_buf;
- conn->push_buf = NULL;
- return buf;
-#else /* GNUTLS_IA */
- return NULL;
-#endif /* GNUTLS_IA */
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
- struct tls_connection *conn)
-{
- if (conn == NULL)
- return -1;
-
- return conn->final_phase_finished;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
- struct tls_connection *conn,
- const u8 *key, size_t key_len)
-{
-#ifdef GNUTLS_IA
- if (conn == NULL || !conn->tls_ia)
- return -1;
-
- if (conn->session_keys) {
- os_memset(conn->session_keys, 0, conn->session_keys_len);
- os_free(conn->session_keys);
- }
- conn->session_keys_len = 0;
-
- if (key) {
- conn->session_keys = os_malloc(key_len);
- if (conn->session_keys == NULL)
- return -1;
- os_memcpy(conn->session_keys, key, key_len);
- conn->session_keys_len = key_len;
- } else {
- conn->session_keys = NULL;
- conn->session_keys_len = 0;
- }
-
return 0;
-#else /* GNUTLS_IA */
- return -1;
-#endif /* GNUTLS_IA */
}
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index cc165f6..f5e31d9 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -290,13 +290,6 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
}
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
- int tls_ia)
-{
- return -1;
-}
-
-
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
@@ -339,6 +332,17 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
+ return tls_connection_handshake2(tls_ctx, conn, in_data, appl_data,
+ NULL);
+}
+
+
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ struct wpabuf **appl_data,
+ int *need_more_data)
+{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
u8 *res, *ad;
size_t res_len, ad_len;
@@ -351,7 +355,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
res = tlsv1_client_handshake(conn->client,
in_data ? wpabuf_head(in_data) : NULL,
in_data ? wpabuf_len(in_data) : 0,
- &res_len, &ad, &ad_len);
+ &res_len, &ad, &ad_len, need_more_data);
if (res == NULL)
return NULL;
out = wpabuf_alloc_ext_data(res, res_len);
@@ -462,23 +466,23 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
+ return tls_connection_decrypt2(tls_ctx, conn, in_data, NULL);
+}
+
+
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ int *need_more_data)
+{
+ if (need_more_data)
+ *need_more_data = 0;
+
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client) {
- struct wpabuf *buf;
- int res;
- buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
- if (buf == NULL)
- return NULL;
- res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
- wpabuf_len(in_data),
- wpabuf_mhead(buf),
- wpabuf_size(buf));
- if (res < 0) {
- wpabuf_free(buf);
- return NULL;
- }
- wpabuf_put(buf, res);
- return buf;
+ return tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
+ wpabuf_len(in_data),
+ need_more_data);
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
@@ -611,28 +615,6 @@ unsigned int tls_capabilities(void *tls_ctx)
}
-struct wpabuf * tls_connection_ia_send_phase_finished(
- void *tls_ctx, struct tls_connection *conn, int final)
-{
- return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
- struct tls_connection *conn)
-{
- return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
- struct tls_connection *conn,
- const u8 *key, size_t key_len)
-{
- return -1;
-}
-
-
int tls_connection_set_session_ticket_cb(void *tls_ctx,
struct tls_connection *conn,
tls_session_ticket_cb cb,
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index 0c836bb..927edf5 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -84,13 +84,6 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
}
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
- int tls_ia)
-{
- return -1;
-}
-
-
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
@@ -205,25 +198,3 @@ unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
- void *tls_ctx, struct tls_connection *conn, int final)
-{
- return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
- struct tls_connection *conn)
-{
- return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
- struct tls_connection *conn,
- const u8 *key, size_t key_len)
-{
- return -1;
-}
diff --git a/src/crypto/tls_nss.c b/src/crypto/tls_nss.c
index ad834b6..09a1e73 100644
--- a/src/crypto/tls_nss.c
+++ b/src/crypto/tls_nss.c
@@ -419,13 +419,6 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
}
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
- int tls_ia)
-{
- return -1;
-}
-
-
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
@@ -649,28 +642,6 @@ unsigned int tls_capabilities(void *tls_ctx)
}
-struct wpabuf * tls_connection_ia_send_phase_finished(
- void *tls_ctx, struct tls_connection *conn, int final)
-{
- return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
- struct tls_connection *conn)
-{
- return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
- struct tls_connection *conn,
- const u8 *key, size_t key_len)
-{
- return -1;
-}
-
-
int tls_connection_set_session_ticket_cb(void *tls_ctx,
struct tls_connection *conn,
tls_session_ticket_cb cb,
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 14ff87e..8374096 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -59,6 +59,7 @@ struct tls_global {
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
void *cb_ctx;
+ int cert_in_cb;
};
static struct tls_global *tls_global = NULL;
@@ -694,6 +695,7 @@ void * tls_init(const struct tls_config *conf)
if (conf) {
tls_global->event_cb = conf->event_cb;
tls_global->cb_ctx = conf->cb_ctx;
+ tls_global->cert_in_cb = conf->cert_in_cb;
}
#ifdef CONFIG_FIPS
@@ -1144,7 +1146,7 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
return;
os_memset(&ev, 0, sizeof(ev));
- if (conn->cert_probe) {
+ if (conn->cert_probe || tls_global->cert_in_cb) {
cert = get_x509_cert(err_cert);
ev.peer_cert.cert = cert;
}
@@ -1661,6 +1663,7 @@ static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
SSL_FILETYPE_ASN1) != 1 &&
+ SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
SSL_FILETYPE_PEM) != 1) {
tls_show_errors(MSG_INFO, __func__,
@@ -2809,35 +2812,6 @@ unsigned int tls_capabilities(void *tls_ctx)
}
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
- int tls_ia)
-{
- return -1;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
- void *tls_ctx, struct tls_connection *conn, int final)
-{
- return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
- struct tls_connection *conn)
-{
- return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
- struct tls_connection *conn,
- const u8 *key, size_t key_len)
-{
- return -1;
-}
-
-
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
/* Pre-shared secred requires a patch to openssl, so this function is
* commented out unless explicitly needed for EAP-FAST in order to be able to
diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c
index 4a94e99..a33d24e 100644
--- a/src/crypto/tls_schannel.c
+++ b/src/crypto/tls_schannel.c
@@ -736,32 +736,3 @@ unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
- int tls_ia)
-{
- return -1;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
- void *tls_ctx, struct tls_connection *conn, int final);
-{
- return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
- struct tls_connection *conn)
-{
- return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
- struct tls_connection *conn,
- const u8 *key, size_t key_len)
-{
- return -1;
-}
diff --git a/src/drivers/Apple80211.h b/src/drivers/Apple80211.h
deleted file mode 100644
index 2a612e7..0000000
--- a/src/drivers/Apple80211.h
+++ /dev/null
@@ -1,156 +0,0 @@
-#ifndef APPLE80211_H
-#define APPLE80211_H
-
-/*
- * Apple80211 framework definitions
- * This is an undocumented interface and the definitions here are based on
- * information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
- * whatever related information can be found with google and experiments ;-).
- */
-
-typedef struct __WirelessRef *WirelessRef;
-typedef SInt32 WirelessError;
-#define errWirelessNoError 0
-
-typedef struct WirelessInfo {
- UInt16 link_qual;
- UInt16 comms_qual;
- UInt16 signal;
- UInt16 noise;
- UInt16 port_stat;
- UInt16 client_mode;
- UInt16 res1;
- UInt16 power;
- UInt16 res2;
- UInt8 bssID[6];
- UInt8 ssid[34];
-} WirelessInfo;
-
-typedef struct WirelessInfo2 {
- /* TODO - these are probably not in correct order or complete */
- WirelessInfo info1;
- UInt8 macAddress[6];
-} WirelessInfo2;
-
-typedef struct WirelessNetworkInfo {
- UInt16 channel;
- UInt16 noise;
- UInt16 signal;
- UInt8 bssid[6];
- UInt16 beacon_int;
- UInt16 capability;
- UInt16 ssid_len;
- UInt8 ssid[32];
-} WirelessNetworkInfo;
-
-typedef int wirelessKeyType; /* TODO */
-
-int WirelessIsAvailable(void);
-WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
-WirelessError WirelessDetach(WirelessRef ref);
-WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
- void *out_ptr, int out_bytes);
-WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
-WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
-WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
-WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
-WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
-WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
-WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
- UInt32 strip_dups);
-WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
- CFArrayRef *ibss_results, UInt32 strip_dups);
-WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
- UInt32 strip_dups, CFStringRef ssid);
-WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
- UInt32 strip_dups, CFArrayRef *results);
-WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
-WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
- CFStringRef passwd);
-WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
-/*
- * Set WEP key
- * ref: wireless reference from WirelessAttach()
- * type: ?
- * key_idx: 0..3
- * key_len: 13 for WEP-104 or 0 for clearing the key
- * key: Pointer to the key or %NULL if key_len = 0
- */
-WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
- int key_idx, int key_len,
- const unsigned char *key);
-/*
- * Set WPA key (e.g., PMK for 4-way handshake)
- * ref: wireless reference from WirelessAttach()
- * type: 0..4; 1 = PMK
- * key_len: 16, 32, or 0
- * key: Pointer to the key or %NULL if key_len = 0
- */
-WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
- int key_len, const unsigned char *key);
-WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
- CFStringRef key);
-WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
- CFStringRef key);
-WirelessError WirelessDisassociate(WirelessRef ref);
-
-/*
- * Get a copy of scan results for the given SSID
- * The returned dictionary includes following entries:
- * beaconInterval: CFNumber(kCFNumberSInt32Type)
- * SSID: CFData buffer of the SSID
- * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
- * name: Name of the network (SSID string)
- * BSSID: CFData buffer of the BSSID
- * channel: CFNumber(kCFNumberSInt32Type)
- * signal: CFNumber(kCFNumberSInt32Type)
- * appleIE: CFData
- * WPSNOPINRequired: CFBoolean
- * noise: CFNumber(kCFNumberSInt32Type)
- * capability: CFNumber(kCFNumberSInt32Type)
- * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
- * appleIE_Version: CFNumber(kCFNumberSInt32Type)
- * appleIE_Robust: CFBoolean
- * WPSConfigured: CFBoolean
- * scanWasDirected: CFBoolean
- * appleIE_Product: CFNumber(kCFNumberSInt32Type)
- * authModes: CFArray of CFNumber(kCFNumberSInt32Type)
- * multiCipher: CFNumber(kCFNumberSInt32Type)
- */
-CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
-
-/*
- * Get information about the current association
- * The returned dictionary includes following entries:
- * keyData: CFData buffer of the key (e.g., 32-octet PSK)
- * multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
- * channel: CFNumber(kCFNumberSInt32Type)
- * isIBSS: CFBoolean
- * authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
- * 129 = WPA2-Enterprise
- * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
- * SSID: CFData buffer of the SSID
- * cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
- */
-CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
-
-WirelessError WirelessConfigure(WirelessRef ref);
-
-/*
- * Get ASP information
- * The returned dictionary includes following entries:
- * Version: version number (e.g., 3.0)
- * Channel: channel (e.g., 1)
- * Vendor: vendor (e.g., 2)
- */
-CFDictionaryRef WirelessGetInfoASP(void);
-
-/*
- * Get a copy of the interface dictionary
- * The returned dictionary has a key,value pairs for wireless interfaces.
- * The key is the interface name and the value is the driver identifier, e.g.,
- * en1: com.apple.driver.AirPort.Atheros
- */
-CFDictionaryRef WirelessCopyInterfaceDict(void);
-
-#endif /* APPLE80211_H */
diff --git a/src/drivers/MobileApple80211.c b/src/drivers/MobileApple80211.c
deleted file mode 100644
index ce004fe..0000000
--- a/src/drivers/MobileApple80211.c
+++ /dev/null
@@ -1,189 +0,0 @@
-#include "includes.h"
-#include <dlfcn.h>
-
-#include "common.h"
-
-#include <CoreFoundation/CoreFoundation.h>
-#include "MobileApple80211.h"
-
-/*
- * Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
- * having to link with full Preferences.framework.
- */
-
-static void *aeropuerto = NULL;
-
-
-int _Apple80211Initialized(void)
-{
- return aeropuerto ? 1 : 0;
-}
-
-
-static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
-
-int Apple80211Open(Apple80211Ref *ctx)
-{
- return __Apple80211Open(ctx);
-}
-
-
-static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
-
-int Apple80211Close(Apple80211Ref ctx)
-{
- return __Apple80211Close(ctx);
-}
-
-
-static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
- = NULL;
-
-int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
-{
- return __Apple80211GetIfListCopy(handle, list);
-}
-
-
-static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
- CFStringRef interface) = NULL;
-
-int Apple80211BindToInterface(Apple80211Ref handle,
- CFStringRef interface)
-{
- return __Apple80211BindToInterface(handle, interface);
-}
-
-
-static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
- CFStringRef *name) = NULL;
-
-int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
- CFStringRef *name)
-{
- return __Apple80211GetInterfaceNameCopy(handle, name);
-}
-
-
-static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
- CFDictionaryRef *info) = NULL;
-
-int Apple80211GetInfoCopy(Apple80211Ref handle,
- CFDictionaryRef *info)
-{
- return __Apple80211GetInfoCopy(handle, info);
-}
-
-
-static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
-
-int Apple80211GetPower(Apple80211Ref handle, char *pwr)
-{
- return __Apple80211GetPower(handle, pwr);
-}
-
-
-static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
-
-int Apple80211SetPower(Apple80211Ref handle, char pwr)
-{
- return __Apple80211SetPower(handle, pwr);
-}
-
-
-static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
- CFDictionaryRef parameters) = NULL;
-
-int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
- CFDictionaryRef parameters)
-{
- return __Apple80211Scan(handle, list, parameters);
-}
-
-
-static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
- CFStringRef password) = NULL;
-
-int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
- CFStringRef password)
-{
- return __Apple80211Associate(handle, bss, password);
-}
-
-
-static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
- CFDictionaryRef bss,
- CFStringRef password,
- CFDictionaryRef *info) =
- NULL;
-
-int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
- CFStringRef password, CFDictionaryRef *info)
-{
- return __Apple80211AssociateAndCopyInfo(handle, bss, password, info);
-}
-
-
-static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
- CFDictionaryRef arg2, void *value) = NULL;
-
-int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
- void *value)
-{
- return __Apple80211CopyValue(handle, field, arg2, value);
-}
-
-
-#define DLSYM(s) \
-do { \
- __ ## s = dlsym(aeropuerto, #s); \
- if (__ ## s == NULL) { \
- wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
- "symbol '" #s "' (%s)", dlerror()); \
- err = 1; \
- } \
-} while (0)
-
-
-__attribute__ ((constructor))
-void _Apple80211_constructor(void)
-{
- const char *fname = "/System/Library/SystemConfiguration/"
- "Aeropuerto.bundle/Aeropuerto";
- int err = 0;
-
- aeropuerto = dlopen(fname, RTLD_LAZY);
- if (!aeropuerto) {
- wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
- "for symbols", fname);
- return;
- }
-
- DLSYM(Apple80211Open);
- DLSYM(Apple80211Close);
- DLSYM(Apple80211GetIfListCopy);
- DLSYM(Apple80211BindToInterface);
- DLSYM(Apple80211GetInterfaceNameCopy);
- DLSYM(Apple80211GetInfoCopy);
- DLSYM(Apple80211GetPower);
- DLSYM(Apple80211SetPower);
- DLSYM(Apple80211Scan);
- DLSYM(Apple80211Associate);
- DLSYM(Apple80211AssociateAndCopyInfo);
- DLSYM(Apple80211CopyValue);
-
- if (err) {
- dlclose(aeropuerto);
- aeropuerto = NULL;
- }
-}
-
-
-__attribute__ ((destructor))
-void _Apple80211_destructor(void)
-{
- if (aeropuerto) {
- dlclose(aeropuerto);
- aeropuerto = NULL;
- }
-}
diff --git a/src/drivers/MobileApple80211.h b/src/drivers/MobileApple80211.h
deleted file mode 100644
index 64d439d..0000000
--- a/src/drivers/MobileApple80211.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef MOBILEAPPLE80211_H
-#define MOBILEAPPLE80211_H
-
-/*
- * MobileApple80211 interface for iPhone/iPod touch
- * These functions are available from Aeropuerto.
- */
-
-struct Apple80211;
-typedef struct Apple80211 *Apple80211Ref;
-
-int Apple80211Open(Apple80211Ref *ctx);
-int Apple80211Close(Apple80211Ref ctx);
-int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
-int Apple80211BindToInterface(Apple80211Ref handle,
- CFStringRef interface);
-int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
- CFStringRef *name);
-int Apple80211GetInfoCopy(Apple80211Ref handle,
- CFDictionaryRef *info);
-int Apple80211GetPower(Apple80211Ref handle, char *pwr);
-int Apple80211SetPower(Apple80211Ref handle, char pwr);
-
-/* parameters can be NULL; returns scan results in CFArrayRef *list;
- * caller will need to free with CFRelease() */
-int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
- CFDictionaryRef parameters);
-
-int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
- CFStringRef password);
-int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
- CFStringRef password,
- CFDictionaryRef *info);
-
-enum {
- APPLE80211_VALUE_SSID = 1,
- APPLE80211_VALUE_BSSID = 9
-};
-
-int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
- void *value);
-
-#endif /* MOBILEAPPLE80211_H */
diff --git a/src/drivers/android_drv.h b/src/drivers/android_drv.h
new file mode 100644
index 0000000..6df7160
--- /dev/null
+++ b/src/drivers/android_drv.h
@@ -0,0 +1,62 @@
+/*
+ * Android driver interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ */
+
+#ifndef ANDROID_DRV_H
+#define ANDROID_DRV_H
+
+#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE "
+
+#define WEXT_CSCAN_AMOUNT 9
+
+#define MAX_SSID_LEN 32
+
+#define MAX_DRV_CMD_SIZE 248
+#define DRV_NUMBER_SEQUENTIAL_ERRORS 4
+
+#define WEXT_PNOSETUP_HEADER "PNOSETUP "
+#define WEXT_PNOSETUP_HEADER_SIZE 9
+#define WEXT_PNO_TLV_PREFIX 'S'
+#define WEXT_PNO_TLV_VERSION '1'
+#define WEXT_PNO_TLV_SUBVERSION '2'
+#define WEXT_PNO_TLV_RESERVED '0'
+#define WEXT_PNO_VERSION_SIZE 4
+#define WEXT_PNO_AMOUNT 16
+#define WEXT_PNO_SSID_SECTION 'S'
+/* SSID header size is SSID section type above + SSID length */
+#define WEXT_PNO_SSID_HEADER_SIZE 2
+#define WEXT_PNO_SCAN_INTERVAL_SECTION 'T'
+#define WEXT_PNO_SCAN_INTERVAL_LENGTH 2
+#define WEXT_PNO_SCAN_INTERVAL 30
+/* Scan interval size is scan interval section type + scan interval length
+ * above */
+#define WEXT_PNO_SCAN_INTERVAL_SIZE (1 + WEXT_PNO_SCAN_INTERVAL_LENGTH)
+#define WEXT_PNO_REPEAT_SECTION 'R'
+#define WEXT_PNO_REPEAT_LENGTH 1
+#define WEXT_PNO_REPEAT 4
+/* Repeat section size is Repeat section type + Repeat value length above */
+#define WEXT_PNO_REPEAT_SIZE (1 + WEXT_PNO_REPEAT_LENGTH)
+#define WEXT_PNO_MAX_REPEAT_SECTION 'M'
+#define WEXT_PNO_MAX_REPEAT_LENGTH 1
+#define WEXT_PNO_MAX_REPEAT 3
+/* Max Repeat section size is Max Repeat section type + Max Repeat value length
+ * above */
+#define WEXT_PNO_MAX_REPEAT_SIZE (1 + WEXT_PNO_MAX_REPEAT_LENGTH)
+/* This corresponds to the size of all sections expect SSIDs */
+#define WEXT_PNO_NONSSID_SECTIONS_SIZE \
+(WEXT_PNO_SCAN_INTERVAL_SIZE + WEXT_PNO_REPEAT_SIZE + WEXT_PNO_MAX_REPEAT_SIZE)
+/* PNO Max command size is total of header, version, ssid and other sections +
+ * Null termination */
+#define WEXT_PNO_MAX_COMMAND_SIZE \
+ (WEXT_PNOSETUP_HEADER_SIZE + WEXT_PNO_VERSION_SIZE \
+ + WEXT_PNO_AMOUNT * (WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN) \
+ + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1)
+
+#endif /* ANDROID_DRV_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 19f732d..ceed531 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -35,14 +35,6 @@
#define HOSTAPD_CHAN_HT40MINUS 0x00000020
#define HOSTAPD_CHAN_HT40 0x00000040
-#ifdef ANDROID_BRCM_P2P_PATCH
-/**
- * Monitor interface name is derived from p2p interface name
- * We need to reset p2p interface name early to take care of extra character in
- */
-#define WPA_MONITOR_IFNAME_PREFIX "m."
-#endif
-
/**
* struct hostapd_channel_data - Channel information
*/
@@ -68,6 +60,8 @@ struct hostapd_channel_data {
u8 max_tx_power;
};
+#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
+
/**
* struct hostapd_hw_modes - Supported hardware mode information
*/
@@ -111,6 +105,8 @@ struct hostapd_hw_modes {
* a_mpdu_params - A-MPDU (IEEE 802.11n) parameters
*/
u8 a_mpdu_params;
+
+ unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
};
@@ -203,7 +199,7 @@ struct wpa_interface_info {
const char *drv_name;
};
-#define WPAS_MAX_SCAN_SSIDS 10
+#define WPAS_MAX_SCAN_SSIDS 16
/**
* struct wpa_driver_scan_params - Scan parameters
@@ -272,6 +268,15 @@ struct wpa_driver_scan_params {
* num_filter_ssids - Number of entries in filter_ssids array
*/
size_t num_filter_ssids;
+
+ /**
+ * p2p_probe - Used to disable CCK (802.11b) rates for P2P probes
+ *
+ * When set, the driver is expected to remove rates 1, 2, 5.5, and 11
+ * Mbps from the support rates element(s) in the Probe Request frames
+ * and not to transmit the frames at any of those rates.
+ */
+ u8 p2p_probe;
};
/**
@@ -290,6 +295,12 @@ struct wpa_driver_auth_params {
size_t wep_key_len[4];
int wep_tx_keyidx;
int local_state_change;
+
+ /**
+ * p2p - Whether this connection is a P2P group
+ */
+ int p2p;
+
};
enum wps_mode {
@@ -353,6 +364,11 @@ struct wpa_driver_associate_params {
size_t wpa_ie_len;
/**
+ * wpa_proto - Bitfield of WPA_PROTO_* values to indicate WPA/WPA2
+ */
+ unsigned int wpa_proto;
+
+ /**
* pairwise_suite - Selected pairwise cipher suite
*
* This is usually ignored if @wpa_ie is used.
@@ -502,6 +518,183 @@ struct wpa_driver_associate_params {
int uapsd;
};
+enum hide_ssid {
+ NO_SSID_HIDING,
+ HIDDEN_SSID_ZERO_LEN,
+ HIDDEN_SSID_ZERO_CONTENTS
+};
+
+struct wpa_driver_ap_params {
+ /**
+ * head - Beacon head from IEEE 802.11 header to IEs before TIM IE
+ */
+ const u8 *head;
+
+ /**
+ * head_len - Length of the head buffer in octets
+ */
+ size_t head_len;
+
+ /**
+ * tail - Beacon tail following TIM IE
+ */
+ const u8 *tail;
+
+ /**
+ * tail_len - Length of the tail buffer in octets
+ */
+ size_t tail_len;
+
+ /**
+ * dtim_period - DTIM period
+ */
+ int dtim_period;
+
+ /**
+ * beacon_int - Beacon interval
+ */
+ int beacon_int;
+
+ /**
+ * basic_rates: -1 terminated array of basic rates in 100 kbps
+ *
+ * This parameter can be used to set a specific basic rate set for the
+ * BSS. If %NULL, default basic rate set is used.
+ */
+ int *basic_rates;
+
+ /**
+ * proberesp - Probe Response template
+ *
+ * This is used by drivers that reply to Probe Requests internally in
+ * AP mode and require the full Probe Response template.
+ */
+ const u8 *proberesp;
+
+ /**
+ * proberesp_len - Length of the proberesp buffer in octets
+ */
+ size_t proberesp_len;
+
+ /**
+ * ssid - The SSID to use in Beacon/Probe Response frames
+ */
+ const u8 *ssid;
+
+ /**
+ * ssid_len - Length of the SSID (1..32)
+ */
+ size_t ssid_len;
+
+ /**
+ * hide_ssid - Whether to hide the SSID
+ */
+ enum hide_ssid hide_ssid;
+
+ /**
+ * pairwise_ciphers - WPA_CIPHER_* bitfield
+ */
+ unsigned int pairwise_ciphers;
+
+ /**
+ * group_cipher - WPA_CIPHER_*
+ */
+ unsigned int group_cipher;
+
+ /**
+ * key_mgmt_suites - WPA_KEY_MGMT_* bitfield
+ */
+ unsigned int key_mgmt_suites;
+
+ /**
+ * auth_algs - WPA_AUTH_ALG_* bitfield
+ */
+ unsigned int auth_algs;
+
+ /**
+ * wpa_version - WPA_PROTO_* bitfield
+ */
+ unsigned int wpa_version;
+
+ /**
+ * privacy - Whether privacy is used in the BSS
+ */
+ int privacy;
+
+ /**
+ * beacon_ies - WPS/P2P IE(s) for Beacon frames
+ *
+ * This is used to add IEs like WPS IE and P2P IE by drivers that do
+ * not use the full Beacon template.
+ */
+ const struct wpabuf *beacon_ies;
+
+ /**
+ * proberesp_ies - P2P/WPS IE(s) for Probe Response frames
+ *
+ * This is used to add IEs like WPS IE and P2P IE by drivers that
+ * reply to Probe Request frames internally.
+ */
+ const struct wpabuf *proberesp_ies;
+
+ /**
+ * assocresp_ies - WPS IE(s) for (Re)Association Response frames
+ *
+ * This is used to add IEs like WPS IE by drivers that reply to
+ * (Re)Association Request frames internally.
+ */
+ const struct wpabuf *assocresp_ies;
+
+ /**
+ * isolate - Whether to isolate frames between associated stations
+ *
+ * If this is non-zero, the AP is requested to disable forwarding of
+ * frames between associated stations.
+ */
+ int isolate;
+
+ /**
+ * cts_protect - Whether CTS protection is enabled
+ */
+ int cts_protect;
+
+ /**
+ * preamble - Whether short preamble is enabled
+ */
+ int preamble;
+
+ /**
+ * short_slot_time - Whether short slot time is enabled
+ *
+ * 0 = short slot time disable, 1 = short slot time enabled, -1 = do
+ * not set (e.g., when 802.11g mode is not in use)
+ */
+ int short_slot_time;
+
+ /**
+ * ht_opmode - HT operation mode or -1 if HT not in use
+ */
+ int ht_opmode;
+
+ /**
+ * interworking - Whether Interworking is enabled
+ */
+ int interworking;
+
+ /**
+ * hessid - Homogeneous ESS identifier or %NULL if not set
+ */
+ const u8 *hessid;
+
+ /**
+ * access_network_type - Access Network Type (0..15)
+ *
+ * This is used for filtering Probe Request frames when Interworking is
+ * enabled.
+ */
+ u8 access_network_type;
+};
+
/**
* struct wpa_driver_capa - Driver capability information
*/
@@ -530,7 +723,7 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_DRIVER_IE 0x00000001
/* Driver needs static WEP key setup after association command */
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
-#define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004
+/* unused: 0x00000004 */
/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
* struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
@@ -571,9 +764,24 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000
/* Driver indicates TX status events for EAPOL Data frames */
#define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS 0x00010000
+/* Driver indicates TX status events for Deauth/Disassoc frames */
+#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS 0x00020000
+/* Driver supports roaming (BSS selection) in firmware */
+#define WPA_DRIVER_FLAGS_BSS_SELECTION 0x00040000
+/* Driver supports operating as a TDLS peer */
+#define WPA_DRIVER_FLAGS_TDLS_SUPPORT 0x00080000
+/* Driver requires external TDLS setup/teardown/discovery */
+#define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP 0x00100000
+/* Driver indicates support for Probe Response offloading in AP mode */
+#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD 0x00200000
+/* Driver supports U-APSD in AP mode */
+#define WPA_DRIVER_FLAGS_AP_UAPSD 0x00400000
unsigned int flags;
int max_scan_ssids;
+ int max_sched_scan_ssids;
+ int sched_scan_supported;
+ int max_match_sets;
/**
* max_remain_on_chan - Maximum remain-on-channel duration in msec
@@ -585,6 +793,20 @@ struct wpa_driver_capa {
* supports in AP mode
*/
unsigned int max_stations;
+
+ /**
+ * probe_resp_offloads - Bitmap of supported protocols by the driver
+ * for Probe Response offloading.
+ */
+/* Driver Probe Response offloading support for WPS ver. 1 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS 0x00000001
+/* Driver Probe Response offloading support for WPS ver. 2 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2 0x00000002
+/* Driver Probe Response offloading support for P2P */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P 0x00000004
+/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008
+ unsigned int probe_resp_offloads;
};
@@ -610,6 +832,9 @@ struct hostapd_sta_add_params {
size_t supp_rates_len;
u16 listen_interval;
const struct ieee80211_ht_capabilities *ht_capabilities;
+ u32 flags; /* bitmask of WPA_STA_* flags */
+ int set; /* Set STA parameters instead of add */
+ u8 qosinfo;
};
struct hostapd_freq_params {
@@ -661,6 +886,7 @@ enum wpa_driver_if_type {
};
struct wpa_init_params {
+ void *global_priv;
const u8 *bssid;
const char *ifname;
const u8 *ssid;
@@ -693,6 +919,7 @@ struct wpa_bss_params {
#define WPA_STA_WMM BIT(1)
#define WPA_STA_SHORT_PREAMBLE BIT(2)
#define WPA_STA_MFP BIT(3)
+#define WPA_STA_TDLS_PEER BIT(4)
/**
* struct p2p_params - P2P parameters for driver-based P2P management
@@ -1079,91 +1306,21 @@ struct wpa_driver_ops {
* flags: Variable for returning hardware feature flags
* Returns: Pointer to allocated hardware data on success or %NULL on
* failure. Caller is responsible for freeing this.
- *
- * This function is only needed for drivers that export MLME
- * (management frame processing) to %wpa_supplicant or hostapd.
*/
struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
u16 *num_modes,
u16 *flags);
/**
- * set_channel - Set channel
- * @priv: Private driver interface data
- * @phymode: HOSTAPD_MODE_IEEE80211B, ..
- * @chan: IEEE 802.11 channel number
- * @freq: Frequency of the channel in MHz
- * Returns: 0 on success, -1 on failure
- *
- * This function is only needed for drivers that export MLME
- * (management frame processing) to wpa_supplicant.
- */
- int (*set_channel)(void *priv, enum hostapd_hw_mode phymode, int chan,
- int freq);
-
- /**
- * set_ssid - Set SSID
- * @priv: Private driver interface data
- * @ssid: SSID
- * @ssid_len: SSID length
- * Returns: 0 on success, -1 on failure
- *
- * This function is only needed for drivers that export MLME
- * (management frame processing) to wpa_supplicant.
- */
- int (*set_ssid)(void *priv, const u8 *ssid, size_t ssid_len);
-
- /**
- * set_bssid - Set BSSID
- * @priv: Private driver interface data
- * @bssid: BSSID
- * Returns: 0 on success, -1 on failure
- *
- * This function is only needed for drivers that export MLME
- * (management frame processing) to wpa_supplicant.
- */
- int (*set_bssid)(void *priv, const u8 *bssid);
-
- /**
* send_mlme - Send management frame from MLME
* @priv: Private driver interface data
* @data: IEEE 802.11 management frame with IEEE 802.11 header
* @data_len: Size of the management frame
+ * @noack: Do not wait for this frame to be acked (disable retries)
* Returns: 0 on success, -1 on failure
- *
- * This function is only needed for drivers that export MLME
- * (management frame processing) to wpa_supplicant.
*/
- int (*send_mlme)(void *priv, const u8 *data, size_t data_len);
-
- /**
- * mlme_add_sta - Add a STA entry into the driver/netstack
- * @priv: Private driver interface data
- * @addr: MAC address of the STA (e.g., BSSID of the AP)
- * @supp_rates: Supported rate set (from (Re)AssocResp); in IEEE 802.11
- * format (one octet per rate, 1 = 0.5 Mbps)
- * @supp_rates_len: Number of entries in supp_rates
- * Returns: 0 on success, -1 on failure
- *
- * This function is only needed for drivers that export MLME
- * (management frame processing) to wpa_supplicant. When the MLME code
- * completes association with an AP, this function is called to
- * configure the driver/netstack with a STA entry for data frame
- * processing (TX rate control, encryption/decryption).
- */
- int (*mlme_add_sta)(void *priv, const u8 *addr, const u8 *supp_rates,
- size_t supp_rates_len);
-
- /**
- * mlme_remove_sta - Remove a STA entry from the driver/netstack
- * @priv: Private driver interface data
- * @addr: MAC address of the STA (e.g., BSSID of the AP)
- * Returns: 0 on success, -1 on failure
- *
- * This function is only needed for drivers that export MLME
- * (management frame processing) to wpa_supplicant.
- */
- int (*mlme_remove_sta)(void *priv, const u8 *addr);
+ int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
+ int noack);
/**
* update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -1292,24 +1449,25 @@ struct wpa_driver_ops {
struct wpa_driver_auth_params *params);
/**
- * set_beacon - Set Beacon frame template
+ * set_ap - Set Beacon and Probe Response information for AP mode
* @priv: Private driver interface data
- * @head: Beacon head from IEEE 802.11 header to IEs before TIM IE
- * @head_len: Length of the head buffer in octets
- * @tail: Beacon tail following TIM IE
- * @tail_len: Length of the tail buffer in octets
- * @dtim_period: DTIM period
- * @beacon_int: Beacon interval
- * Returns: 0 on success, -1 on failure
+ * @params: Parameters to use in AP mode
*
- * This function is used to configure Beacon template for the driver in
+ * This function is used to configure Beacon template and/or extra IEs
+ * to add for Beacon and Probe Response frames for the driver in
* AP mode. The driver is responsible for building the full Beacon
* frame by concatenating the head part with TIM IE generated by the
- * driver/firmware and finishing with the tail part.
+ * driver/firmware and finishing with the tail part. Depending on the
+ * driver architectue, this can be done either by using the full
+ * template or the set of additional IEs (e.g., WPS and P2P IE).
+ * Similarly, Probe Response processing depends on the driver design.
+ * If the driver (or firmware) takes care of replying to Probe Request
+ * frames, the extra IEs provided here needs to be added to the Probe
+ * Response frames.
+ *
+ * Returns: 0 on success, -1 on failure
*/
- int (*set_beacon)(void *priv, const u8 *head, size_t head_len,
- const u8 *tail, size_t tail_len, int dtim_period,
- int beacon_int);
+ int (*set_ap)(void *priv, struct wpa_driver_ap_params *params);
/**
* hapd_init - Initialize driver interface (hostapd only)
@@ -1318,7 +1476,7 @@ struct wpa_driver_ops {
* Returns: Pointer to private data, %NULL on failure
*
* This function is used instead of init() or init2() when the driver
- * wrapper is used withh hostapd.
+ * wrapper is used with hostapd.
*/
void * (*hapd_init)(struct hostapd_data *hapd,
struct wpa_init_params *params);
@@ -1338,8 +1496,10 @@ struct wpa_driver_ops {
* This is an optional function to configure the kernel driver to
* enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This
* can be left undefined (set to %NULL) if IEEE 802.1X support is
- * always enabled and the driver uses set_beacon() to set WPA/RSN IE
+ * always enabled and the driver uses set_ap() to set WPA/RSN IE
* for Beacon frames.
+ *
+ * DEPRECATED - use set_ap() instead
*/
int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params);
@@ -1351,7 +1511,9 @@ struct wpa_driver_ops {
*
* This is an optional function to configure privacy field in the
* kernel driver for Beacon frames. This can be left undefined (set to
- * %NULL) if the driver uses the Beacon template from set_beacon().
+ * %NULL) if the driver uses the Beacon template from set_ap().
+ *
+ * DEPRECATED - use set_ap() instead
*/
int (*set_privacy)(void *priv, int enabled);
@@ -1393,7 +1555,9 @@ struct wpa_driver_ops {
* This is an optional function to add information elements in the
* kernel driver for Beacon and Probe Response frames. This can be left
* undefined (set to %NULL) if the driver uses the Beacon template from
- * set_beacon().
+ * set_ap().
+ *
+ * DEPRECATED - use set_ap() instead
*/
int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
@@ -1467,8 +1631,7 @@ struct wpa_driver_ops {
* Returns: Length of the SSID on success, -1 on failure
*
* This function need not be implemented if the driver uses Beacon
- * template from set_beacon() and does not reply to Probe Request
- * frames.
+ * template from set_ap() and does not reply to Probe Request frames.
*/
int (*hapd_get_ssid)(void *priv, u8 *buf, int len);
@@ -1478,6 +1641,8 @@ struct wpa_driver_ops {
* @buf: SSID
* @len: Length of the SSID in octets
* Returns: 0 on success, -1 on failure
+ *
+ * DEPRECATED - use set_ap() instead
*/
int (*hapd_set_ssid)(void *priv, const u8 *buf, int len);
@@ -1501,6 +1666,9 @@ struct wpa_driver_ops {
* This function is used to add a station entry to the driver once the
* station has completed association. This is only used if the driver
* does not take care of association processing.
+ *
+ * With TDLS, this function is also used to add or set (params->set 1)
+ * TDLS peer entries.
*/
int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
@@ -1557,41 +1725,6 @@ struct wpa_driver_ops {
int total_flags, int flags_or, int flags_and);
/**
- * set_rate_sets - Set supported and basic rate sets (AP only)
- * @priv: Private driver interface data
- * @supp_rates: -1 terminated array of supported rates in 100 kbps
- * @basic_rates: -1 terminated array of basic rates in 100 kbps
- * @mode: hardware mode (HOSTAPD_MODE_*)
- * Returns: 0 on success, -1 on failure
- */
- int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
- int mode);
-
- /**
- * set_cts_protect - Set CTS protection mode (AP only)
- * @priv: Private driver interface data
- * @value: Whether CTS protection is enabled
- * Returns: 0 on success, -1 on failure
- */
- int (*set_cts_protect)(void *priv, int value);
-
- /**
- * set_preamble - Set preamble mode (AP only)
- * @priv: Private driver interface data
- * @value: Whether short preamble is enabled
- * Returns: 0 on success, -1 on failure
- */
- int (*set_preamble)(void *priv, int value);
-
- /**
- * set_short_slot_time - Set short slot time (AP only)
- * @priv: Private driver interface data
- * @value: Whether short slot time is enabled
- * Returns: 0 on success, -1 on failure
- */
- int (*set_short_slot_time)(void *priv, int value);
-
- /**
* set_tx_queue_params - Set TX queue parameters
* @priv: Private driver interface data
* @queue: Queue number (0 = VO, 1 = VI, 2 = BE, 3 = BK)
@@ -1604,17 +1737,6 @@ struct wpa_driver_ops {
int cw_max, int burst_time);
/**
- * valid_bss_mask - Validate BSSID mask
- * @priv: Private driver interface data
- * @addr: Address
- * @mask: Mask
- * Returns: 0 if mask is valid, -1 if mask is not valid, 1 if mask can
- * be used, but the main interface address must be the first address in
- * the block if mask is applied
- */
- int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask);
-
- /**
* if_add - Add a virtual interface
* @priv: Private driver interface data
* @type: Interface type
@@ -1709,19 +1831,6 @@ struct wpa_driver_ops {
int (*set_radius_acl_expire)(void *priv, const u8 *mac);
/**
- * set_ht_params - Set HT parameters (AP only)
- * @priv: Private driver interface data
- * @ht_capab: HT Capabilities IE
- * @ht_capab_len: Length of ht_capab in octets
- * @ht_oper: HT Operation IE
- * @ht_oper_len: Length of ht_oper in octets
- * Returns: 0 on success, -1 on failure
- */
- int (*set_ht_params)(void *priv,
- const u8 *ht_capab, size_t ht_capab_len,
- const u8 *ht_oper, size_t ht_oper_len);
-
- /**
* set_ap_wps_ie - Add WPS IE(s) into Beacon/Probe Response frames (AP)
* @priv: Private driver interface data
* @beacon: WPS IE(s) for Beacon frames or %NULL to remove extra IE(s)
@@ -1733,7 +1842,7 @@ struct wpa_driver_ops {
*
* This is an optional function to add WPS IE in the kernel driver for
* Beacon and Probe Response frames. This can be left undefined (set
- * to %NULL) if the driver uses the Beacon template from set_beacon()
+ * to %NULL) if the driver uses the Beacon template from set_ap()
* and does not process Probe Request frames. If the driver takes care
* of (Re)Association frame processing, the assocresp buffer includes
* WPS IE(s) that need to be added to (Re)Association Response frames
@@ -1746,6 +1855,8 @@ struct wpa_driver_ops {
* also used to provide Probe Response IEs for P2P Listen state
* operations for drivers that generate the Probe Response frames
* internally.
+ *
+ * DEPRECATED - use set_ap() instead
*/
int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon,
const struct wpabuf *proberesp,
@@ -1782,6 +1893,7 @@ struct wpa_driver_ops {
* @bssid: BSSID (Address 3)
* @data: Frame body
* @data_len: data length in octets
+ @ @no_cck: Whether CCK rates must not be used to transmit this frame
* Returns: 0 on success, -1 on failure
*
* This command can be used to request the driver to transmit an action
@@ -1799,7 +1911,7 @@ struct wpa_driver_ops {
*/
int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
const u8 *dst, const u8 *src, const u8 *bssid,
- const u8 *data, size_t data_len);
+ const u8 *data, size_t data_len, int no_cck);
/**
* send_action_cancel_wait - Cancel action frame TX wait
@@ -1866,19 +1978,6 @@ struct wpa_driver_ops {
int (*probe_req_report)(void *priv, int report);
/**
- * disable_11b_rates - Set whether IEEE 802.11b rates are used for TX
- * @priv: Private driver interface data
- * @disabled: Whether IEEE 802.11b rates are disabled
- * Returns: 0 on success, -1 on failure (or if not supported)
- *
- * This command is used to disable IEEE 802.11b rates (1, 2, 5.5, and
- * 11 Mbps) as TX rates for data and management frames. This can be
- * used to optimize channel use when there is no need to support IEEE
- * 802.11b-only devices.
- */
- int (*disable_11b_rates)(void *priv, int disabled);
-
- /**
* deinit_ap - Deinitialize AP mode
* @priv: Private driver interface data
* Returns: 0 on success, -1 on failure (or if not supported)
@@ -1990,11 +2089,6 @@ struct wpa_driver_ops {
int (*ampdu)(void *priv, int ampdu);
/**
- * set_intra_bss - Enables/Disables intra BSS bridging
- */
- int (*set_intra_bss)(void *priv, int enabled);
-
- /**
* get_radio_name - Get physical radio name for the device
* @priv: Private driver interface data
* Returns: Radio name or %NULL if not known
@@ -2132,7 +2226,7 @@ struct wpa_driver_ops {
* struct wpa_driver_capa.
*/
int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr,
- u16 config_methods);
+ u16 config_methods, int join);
/**
* p2p_sd_request - Schedule a service discovery query
@@ -2232,7 +2326,7 @@ struct wpa_driver_ops {
* @status_code: Status Code or Reason Code to use (if needed)
* @buf: TDLS IEs to add to the message
* @len: Length of buf in octets
- * Returns: 0 on success, -1 on failure
+ * Returns: 0 on success, negative (<0) on failure
*
* This optional function can be used to send packet to driver which is
* responsible for receiving and sending all TDLS packets.
@@ -2241,6 +2335,16 @@ struct wpa_driver_ops {
u8 dialog_token, u16 status_code,
const u8 *buf, size_t len);
+ /**
+ * tdls_oper - Ask the driver to perform high-level TDLS operations
+ * @priv: Private driver interface data
+ * @oper: TDLS high-level operation. See %enum tdls_oper
+ * @peer: Destination (peer) MAC address
+ * Returns: 0 on success, negative (<0) on failure
+ *
+ * This optional function can be used to send high-level TDLS commands
+ * to the driver.
+ */
int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
/**
@@ -2259,9 +2363,11 @@ struct wpa_driver_ops {
* This function can be used to set authentication algorithms for AP
* mode when static WEP is used. If the driver uses user space MLME/SME
* implementation, there is no need to implement this function.
+ *
+ * DEPRECATED - use set_ap() instead
*/
int (*set_authmode)(void *priv, int authmode);
-
+#ifdef ANDROID
/**
* driver_cmd - execute driver-specific command
* @priv: private driver interface data
@@ -2272,6 +2378,135 @@ struct wpa_driver_ops {
* Returns: 0 on success, -1 on failure
*/
int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len);
+#endif
+ /**
+ * set_rekey_info - Set rekey information
+ * @priv: Private driver interface data
+ * @kek: Current KEK
+ * @kck: Current KCK
+ * @replay_ctr: Current EAPOL-Key Replay Counter
+ *
+ * This optional function can be used to provide information for the
+ * driver/firmware to process EAPOL-Key frames in Group Key Handshake
+ * while the host (including wpa_supplicant) is sleeping.
+ */
+ void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
+ const u8 *replay_ctr);
+
+ /**
+ * sta_assoc - Station association indication
+ * @priv: Private driver interface data
+ * @own_addr: Source address and BSSID for association frame
+ * @addr: MAC address of the station to associate
+ * @reassoc: flag to indicate re-association
+ * @status: association response status code
+ * @ie: assoc response ie buffer
+ * @len: ie buffer length
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function indicates the driver to send (Re)Association
+ * Response frame to the station.
+ */
+ int (*sta_assoc)(void *priv, const u8 *own_addr, const u8 *addr,
+ int reassoc, u16 status, const u8 *ie, size_t len);
+
+ /**
+ * sta_auth - Station authentication indication
+ * @priv: Private driver interface data
+ * @own_addr: Source address and BSSID for authentication frame
+ * @addr: MAC address of the station to associate
+ * @seq: authentication sequence number
+ * @status: authentication response status code
+ * @ie: authentication frame ie buffer
+ * @len: ie buffer length
+ *
+ * This function indicates the driver to send Authentication frame
+ * to the station.
+ */
+ int (*sta_auth)(void *priv, const u8 *own_addr, const u8 *addr,
+ u16 seq, u16 status, const u8 *ie, size_t len);
+
+ /**
+ * add_tspec - Add traffic stream
+ * @priv: Private driver interface data
+ * @addr: MAC address of the station to associate
+ * @tspec_ie: tspec ie buffer
+ * @tspec_ielen: tspec ie length
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function adds the traffic steam for the station
+ * and fills the medium_time in tspec_ie.
+ */
+ int (*add_tspec)(void *priv, const u8 *addr, u8 *tspec_ie,
+ size_t tspec_ielen);
+
+ /**
+ * add_sta_node - Add a station node in the driver
+ * @priv: Private driver interface data
+ * @addr: MAC address of the station to add
+ * @auth_alg: authentication algorithm used by the station
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function adds the station node in the driver, when
+ * the station gets added by FT-over-DS.
+ */
+ int (*add_sta_node)(void *priv, const u8 *addr, u16 auth_alg);
+
+ /**
+ * sched_scan - Request the driver to initiate scheduled scan
+ * @priv: Private driver interface data
+ * @params: Scan parameters
+ * @interval: Interval between scan cycles in milliseconds
+ * Returns: 0 on success, -1 on failure
+ *
+ * This operation should be used for scheduled scan offload to
+ * the hardware. Every time scan results are available, the
+ * driver should report scan results event for wpa_supplicant
+ * which will eventually request the results with
+ * wpa_driver_get_scan_results2(). This operation is optional
+ * and if not provided or if it returns -1, we fall back to
+ * normal host-scheduled scans.
+ */
+ int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params,
+ u32 interval);
+
+ /**
+ * stop_sched_scan - Request the driver to stop a scheduled scan
+ * @priv: Private driver interface data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This should cause the scheduled scan to be stopped and
+ * results should stop being sent. Must be supported if
+ * sched_scan is supported.
+ */
+ int (*stop_sched_scan)(void *priv);
+
+ /**
+ * poll_client - Probe (null data or such) the given station
+ * @priv: Private driver interface data
+ * @own_addr: MAC address of sending interface
+ * @addr: MAC address of the station to probe
+ * @qos: Indicates whether station is QoS station
+ *
+ * This function is used to verify whether an associated station is
+ * still present. This function does not need to be implemented if the
+ * driver provides such inactivity polling mechanism.
+ */
+ void (*poll_client)(void *priv, const u8 *own_addr,
+ const u8 *addr, int qos);
+#ifdef ANDROID_P2P
+ /**
+ * go_switch_channel - Announce channel switch and migrate the GO to a
+ * given frequency.
+ * @priv: Private driver interface data
+ * @freq: frequency in MHz
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to move the GO to the legacy STA channel to avoid
+ * frequency conflict in single channel concurrency.
+ */
+ int (*go_switch_channel)(void *priv, unsigned int freq);
+#endif
};
@@ -2674,7 +2909,35 @@ enum wpa_event_type {
/**
* EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore
*/
- EVENT_IBSS_PEER_LOST
+ EVENT_IBSS_PEER_LOST,
+
+ /**
+ * EVENT_DRIVER_GTK_REKEY - Device/driver did GTK rekey
+ *
+ * This event carries the new replay counter to notify wpa_supplicant
+ * of the current EAPOL-Key Replay Counter in case the driver/firmware
+ * completed Group Key Handshake while the host (including
+ * wpa_supplicant was sleeping).
+ */
+ EVENT_DRIVER_GTK_REKEY,
+
+ /**
+ * EVENT_SCHED_SCAN_STOPPED - Scheduled scan was stopped
+ */
+ EVENT_SCHED_SCAN_STOPPED,
+
+ /**
+ * EVENT_DRIVER_CLIENT_POLL_OK - Station responded to poll
+ *
+ * This event indicates that the station responded to the poll
+ * initiated with @poll_client.
+ */
+ EVENT_DRIVER_CLIENT_POLL_OK,
+
+ /**
+ * EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
+ */
+ EVENT_EAPOL_TX_STATUS
};
@@ -2898,7 +3161,9 @@ union wpa_event_data {
*/
struct auth_info {
u8 peer[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
u16 auth_type;
+ u16 auth_transaction;
u16 status_code;
const u8 *ies;
size_t ies_len;
@@ -2966,8 +3231,9 @@ union wpa_event_data {
* struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events
*/
struct rx_from_unknown {
- const u8 *frame;
- size_t len;
+ const u8 *bssid;
+ const u8 *addr;
+ int wds;
} rx_from_unknown;
/**
@@ -3075,6 +3341,18 @@ union wpa_event_data {
const u8 *sa;
/**
+ * da - Destination address of the received Probe Request frame
+ * or %NULL if not available
+ */
+ const u8 *da;
+
+ /**
+ * bssid - BSSID of the received Probe Request frame or %NULL
+ * if not available
+ */
+ const u8 *bssid;
+
+ /**
* ie - IEs from the Probe Request body
*/
const u8 *ie;
@@ -3206,6 +3484,39 @@ union wpa_event_data {
struct ibss_peer_lost {
u8 peer[ETH_ALEN];
} ibss_peer_lost;
+
+ /**
+ * struct driver_gtk_rekey - Data for EVENT_DRIVER_GTK_REKEY
+ */
+ struct driver_gtk_rekey {
+ const u8 *bssid;
+ const u8 *replay_ctr;
+ } driver_gtk_rekey;
+
+ /**
+ * struct client_poll - Data for EVENT_DRIVER_CLIENT_POLL_OK events
+ * @addr: station address
+ */
+ struct client_poll {
+ u8 addr[ETH_ALEN];
+ } client_poll;
+
+ /**
+ * struct eapol_tx_status
+ * @dst: Original destination
+ * @data: Data starting with IEEE 802.1X header (!)
+ * @data_len: Length of data
+ * @ack: Indicates ack or lost frame
+ *
+ * This corresponds to hapd_send_eapol if the frame sent
+ * there isn't just reported as EVENT_TX_STATUS.
+ */
+ struct eapol_tx_status {
+ const u8 *dst;
+ const u8 *data;
+ int data_len;
+ int ack;
+ } eapol_tx_status;
};
/**
@@ -3258,4 +3569,10 @@ static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data,
wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
}
+/* driver_common.c */
+void wpa_scan_results_free(struct wpa_scan_results *res);
+
+/* Convert wpa_event_type to a string for logging */
+const char * event_to_string(enum wpa_event_type event);
+
#endif /* DRIVER_H */
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 1e78f6e..b17d1a6 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -34,7 +34,7 @@
*/
#define ATH_WPS_IE
-#include "os/linux/include/ieee80211_external.h"
+#include "ieee80211_external.h"
#ifdef CONFIG_WPS
@@ -45,7 +45,7 @@
#endif
#endif /* CONFIG_WPS */
-#include "wireless_copy.h"
+#include "linux_wext.h"
#include "driver.h"
#include "eloop.h"
@@ -641,6 +641,7 @@ atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
(unsigned long) ie_len);
+ wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len);
wpabuf_free(drv->wpa_ie);
drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len);
@@ -658,6 +659,8 @@ atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
wpabuf_len(drv->wps_beacon_ie));
app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie);
}
+ wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)",
+ app_ie->app_buf, app_ie->app_buflen);
set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
sizeof(struct ieee80211req_getset_appiebuf) +
app_ie->app_buflen);
@@ -672,6 +675,8 @@ atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
wpabuf_len(drv->wps_probe_resp_ie);
} else
app_ie->app_buflen = ie_len;
+ wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)",
+ app_ie->app_buf, app_ie->app_buflen);
set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
sizeof(struct ieee80211req_getset_appiebuf) +
app_ie->app_buflen);
@@ -748,6 +753,8 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
os_memset(&event, 0, sizeof(event));
event.rx_probe_req.sa = mgmt->sa;
+ event.rx_probe_req.da = mgmt->da;
+ event.rx_probe_req.bssid = mgmt->bssid;
event.rx_probe_req.ie = mgmt->u.probe_req.variable;
event.rx_probe_req.ie_len =
len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
@@ -785,8 +792,9 @@ atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
u8 buf[512];
struct ieee80211req_getset_appiebuf *beac_ie;
- wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
- (unsigned long) len);
+ wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__,
+ (unsigned long) len, frametype);
+ wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len);
beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
beac_ie->app_frmtype = frametype;
@@ -797,11 +805,15 @@ atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
if (((frametype == IEEE80211_APPIE_FRAME_BEACON) ||
(frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) &&
(drv->wpa_ie != NULL)) {
+ wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE",
+ drv->wpa_ie);
os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie),
wpabuf_len(drv->wpa_ie));
beac_ie->app_buflen += wpabuf_len(drv->wpa_ie);
}
+ wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF",
+ beac_ie->app_buf, beac_ie->app_buflen);
return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
sizeof(struct ieee80211req_getset_appiebuf) +
beac_ie->app_buflen);
@@ -814,6 +826,11 @@ atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
{
struct atheros_driver_data *drv = priv;
+ wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon);
+ wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp",
+ proberesp);
+ wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp",
+ assocresp);
wpabuf_free(drv->wps_beacon_ie);
drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL;
wpabuf_free(drv->wps_probe_resp_ie);
@@ -1332,6 +1349,8 @@ atheros_get_ssid(void *priv, u8 *buf, int len)
os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
iwr.u.essid.pointer = (caddr_t) buf;
iwr.u.essid.length = len;
+ iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ?
+ IW_ESSID_MAX_SIZE : len;
if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
perror("ioctl[SIOCGIWESSID]");
@@ -1374,6 +1393,34 @@ static int atheros_set_authmode(void *priv, int auth_algs)
return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode);
}
+static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
+{
+ /*
+ * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x,
+ * set_generic_elem, and hapd_set_ssid.
+ */
+
+ wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x "
+ "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x "
+ "wpa_version=0x%x privacy=%d interworking=%d",
+ params->pairwise_ciphers, params->group_cipher,
+ params->key_mgmt_suites, params->auth_algs,
+ params->wpa_version, params->privacy, params->interworking);
+ wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID",
+ params->ssid, params->ssid_len);
+ if (params->hessid)
+ wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR,
+ MAC2STR(params->hessid));
+ wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies",
+ params->beacon_ies);
+ wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies",
+ params->proberesp_ies);
+ wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies",
+ params->assocresp_ies);
+
+ return 0;
+}
+
const struct wpa_driver_ops wpa_driver_atheros_ops = {
.name = "atheros",
.hapd_init = atheros_init,
@@ -1396,4 +1443,5 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = {
.commit = atheros_commit,
.set_ap_wps_ie = atheros_set_ap_wps_ie,
.set_authmode = atheros_set_authmode,
+ .set_ap = atheros_set_ap,
};
diff --git a/src/drivers/driver_broadcom.c b/src/drivers/driver_broadcom.c
deleted file mode 100644
index cb88543..0000000
--- a/src/drivers/driver_broadcom.c
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with old Broadcom wl.o driver
- * Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
- * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * Please note that the newer Broadcom driver ("hybrid Linux driver") supports
- * Linux wireless extensions and does not need (or even work) with this old
- * driver wrapper. Use driver_wext.c with that driver.
- */
-
-#include "includes.h"
-
-#include <sys/ioctl.h>
-
-#include "common.h"
-
-#if 0
-#include <netpacket/packet.h>
-#include <net/ethernet.h> /* the L2 protocols */
-#else
-#include <linux/if_packet.h>
-#include <linux/if_ether.h> /* The L2 protocols */
-#endif
-#include <net/if.h>
-#include <typedefs.h>
-
-/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
- * WRT54G GPL tarball. */
-#include <wlioctl.h>
-
-#include "driver.h"
-#include "eloop.h"
-
-struct wpa_driver_broadcom_data {
- void *ctx;
- int ioctl_sock;
- int event_sock;
- char ifname[IFNAMSIZ + 1];
-};
-
-
-#ifndef WLC_DEAUTHENTICATE
-#define WLC_DEAUTHENTICATE 143
-#endif
-#ifndef WLC_DEAUTHENTICATE_WITH_REASON
-#define WLC_DEAUTHENTICATE_WITH_REASON 201
-#endif
-#ifndef WLC_SET_TKIP_COUNTERMEASURES
-#define WLC_SET_TKIP_COUNTERMEASURES 202
-#endif
-
-#if !defined(PSK_ENABLED) /* NEW driver interface */
-#define WL_VERSION 360130
-/* wireless authentication bit vector */
-#define WPA_ENABLED 1
-#define PSK_ENABLED 2
-
-#define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED)
-#define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED)
-#define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED))
-
-#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
-
-typedef wl_wsec_key_t wsec_key_t;
-#endif
-
-typedef struct {
- uint32 val;
- struct ether_addr ea;
- uint16 res;
-} wlc_deauth_t;
-
-
-static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
- void *timeout_ctx);
-
-static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
- void *buf, int len)
-{
- struct ifreq ifr;
- wl_ioctl_t ioc;
- int ret = 0;
-
- wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
- drv->ifname, cmd, len, buf);
- /* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
-
- ioc.cmd = cmd;
- ioc.buf = buf;
- ioc.len = len;
- os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
- ifr.ifr_data = (caddr_t) &ioc;
- if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
- if (cmd != WLC_GET_MAGIC)
- perror(ifr.ifr_name);
- wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
- cmd, ret);
- }
-
- return ret;
-}
-
-static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
-{
- struct wpa_driver_broadcom_data *drv = priv;
- if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
- return 0;
-
- os_memset(bssid, 0, ETH_ALEN);
- return -1;
-}
-
-static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
-{
- struct wpa_driver_broadcom_data *drv = priv;
- wlc_ssid_t s;
-
- if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
- return -1;
-
- os_memcpy(ssid, s.SSID, s.SSID_len);
- return s.SSID_len;
-}
-
-static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
-{
- struct wpa_driver_broadcom_data *drv = priv;
- unsigned int wauth, wsec;
- struct ether_addr ea;
-
- os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
- if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
- -1 ||
- broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
- return -1;
-
- if (enable) {
- wauth = PSK_ENABLED;
- wsec = TKIP_ENABLED;
- } else {
- wauth = 255;
- wsec &= ~(TKIP_ENABLED | AES_ENABLED);
- }
-
- if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
- -1 ||
- broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
- return -1;
-
- /* FIX: magic number / error handling? */
- broadcom_ioctl(drv, 122, &ea, sizeof(ea));
-
- return 0;
-}
-
-static int wpa_driver_broadcom_set_key(const char *ifname, void *priv,
- enum wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
- struct wpa_driver_broadcom_data *drv = priv;
- int ret;
- wsec_key_t wkt;
-
- os_memset(&wkt, 0, sizeof wkt);
- wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
- set_tx ? "PRIMARY " : "", key_idx, alg);
- if (key && key_len > 0)
- wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
-
- switch (alg) {
- case WPA_ALG_NONE:
- wkt.algo = CRYPTO_ALGO_OFF;
- break;
- case WPA_ALG_WEP:
- wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
- break;
- case WPA_ALG_TKIP:
- wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
- break;
- case WPA_ALG_CCMP:
- wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
- * AES_OCB_MSDU, AES_OCB_MPDU? */
- break;
- default:
- wkt.algo = CRYPTO_ALGO_NALG;
- break;
- }
-
- if (seq && seq_len > 0)
- wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
-
- if (addr)
- wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
-
- wkt.index = key_idx;
- wkt.len = key_len;
- if (key && key_len > 0) {
- os_memcpy(wkt.data, key, key_len);
- if (key_len == 32) {
- /* hack hack hack XXX */
- os_memcpy(&wkt.data[16], &key[24], 8);
- os_memcpy(&wkt.data[24], &key[16], 8);
- }
- }
- /* wkt.algo = CRYPTO_ALGO_...; */
- wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
- if (addr && set_tx)
- os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
- ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
- if (addr && set_tx) {
- /* FIX: magic number / error handling? */
- broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
- }
- return ret;
-}
-
-
-static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
- void *sock_ctx)
-{
- char buf[8192];
- int left;
- wl_wpa_header_t *wwh;
- union wpa_event_data data;
- u8 *resp_ies = NULL;
-
- if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
- return;
-
- wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
-
- if ((size_t) left < sizeof(wl_wpa_header_t))
- return;
-
- wwh = (wl_wpa_header_t *) buf;
-
- if (wwh->snap.type != WL_WPA_ETHER_TYPE)
- return;
- if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
- return;
-
- os_memset(&data, 0, sizeof(data));
-
- switch (wwh->type) {
- case WLC_ASSOC_MSG:
- left -= WL_WPA_HEADER_LEN;
- wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
- left);
- if (left > 0) {
- resp_ies = os_malloc(left);
- if (resp_ies == NULL)
- return;
- os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left);
- data.assoc_info.resp_ies = resp_ies;
- data.assoc_info.resp_ies_len = left;
- }
-
- wpa_supplicant_event(ctx, EVENT_ASSOC, &data);
- os_free(resp_ies);
- break;
- case WLC_DISASSOC_MSG:
- wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
- wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
- break;
- case WLC_PTK_MIC_MSG:
- wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
- data.michael_mic_failure.unicast = 1;
- wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
- break;
- case WLC_GTK_MIC_MSG:
- wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
- data.michael_mic_failure.unicast = 0;
- wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
- break;
- default:
- wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
- wwh->type);
- break;
- }
-}
-
-static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
-{
- int s;
- struct sockaddr_ll ll;
- struct wpa_driver_broadcom_data *drv;
- struct ifreq ifr;
-
- /* open socket to kernel */
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- perror("socket");
- return NULL;
- }
- /* do it */
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
- perror(ifr.ifr_name);
- return NULL;
- }
-
-
- drv = os_zalloc(sizeof(*drv));
- if (drv == NULL)
- return NULL;
- drv->ctx = ctx;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->ioctl_sock = s;
-
- s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
- if (s < 0) {
- perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
- close(drv->ioctl_sock);
- os_free(drv);
- return NULL;
- }
-
- os_memset(&ll, 0, sizeof(ll));
- ll.sll_family = AF_PACKET;
- ll.sll_protocol = ntohs(ETH_P_802_2);
- ll.sll_ifindex = ifr.ifr_ifindex;
- ll.sll_hatype = 0;
- ll.sll_pkttype = PACKET_HOST;
- ll.sll_halen = 0;
-
- if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
- perror("bind(netlink)");
- close(s);
- close(drv->ioctl_sock);
- os_free(drv);
- return NULL;
- }
-
- eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
- NULL);
- drv->event_sock = s;
- wpa_driver_broadcom_set_wpa(drv, 1);
-
- return drv;
-}
-
-static void wpa_driver_broadcom_deinit(void *priv)
-{
- struct wpa_driver_broadcom_data *drv = priv;
- wpa_driver_broadcom_set_wpa(drv, 0);
- eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
- eloop_unregister_read_sock(drv->event_sock);
- close(drv->event_sock);
- close(drv->ioctl_sock);
- os_free(drv);
-}
-
-static int wpa_driver_broadcom_set_countermeasures(void *priv,
- int enabled)
-{
-#if 0
- struct wpa_driver_broadcom_data *drv = priv;
- /* FIX: ? */
- return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
- sizeof(enabled));
-#else
- return 0;
-#endif
-}
-
-static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
-{
- struct wpa_driver_broadcom_data *drv = priv;
- /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
- int _restrict = (enabled ? 1 : 0);
-
- if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
- &_restrict, sizeof(_restrict)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
- &_restrict, sizeof(_restrict)) < 0)
- return -1;
-
- return 0;
-}
-
-static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
- void *timeout_ctx)
-{
- wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
- wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-static int wpa_driver_broadcom_scan(void *priv,
- struct wpa_driver_scan_params *params)
-{
- struct wpa_driver_broadcom_data *drv = priv;
- wlc_ssid_t wst = { 0, "" };
- const u8 *ssid = params->ssids[0].ssid;
- size_t ssid_len = params->ssids[0].ssid_len;
-
- if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
- wst.SSID_len = ssid_len;
- os_memcpy(wst.SSID, ssid, ssid_len);
- }
-
- if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
- return -1;
-
- eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
- eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
- drv->ctx);
- return 0;
-}
-
-
-static const int frequency_list[] = {
- 2412, 2417, 2422, 2427, 2432, 2437, 2442,
- 2447, 2452, 2457, 2462, 2467, 2472, 2484
-};
-
-struct bss_ie_hdr {
- u8 elem_id;
- u8 len;
- u8 oui[3];
- /* u8 oui_type; */
- /* u16 version; */
-} __attribute__ ((packed));
-
-static struct wpa_scan_results *
-wpa_driver_broadcom_get_scan_results(void *priv)
-{
- struct wpa_driver_broadcom_data *drv = priv;
- char *buf;
- wl_scan_results_t *wsr;
- wl_bss_info_t *wbi;
- size_t ap_num;
- struct wpa_scan_results *res;
-
- buf = os_malloc(WLC_IOCTL_MAXLEN);
- if (buf == NULL)
- return NULL;
-
- wsr = (wl_scan_results_t *) buf;
-
- wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
- wsr->version = 107;
- wsr->count = 0;
-
- if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
- os_free(buf);
- return NULL;
- }
-
- res = os_zalloc(sizeof(*res));
- if (res == NULL) {
- os_free(buf);
- return NULL;
- }
-
- res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *));
- if (res->res == NULL) {
- os_free(res);
- os_free(buf);
- return NULL;
- }
-
- for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
- struct wpa_scan_res *r;
- r = os_malloc(sizeof(*r) + wbi->ie_length);
- if (r == NULL)
- break;
- res->res[res->num++] = r;
-
- os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN);
- r->freq = frequency_list[wbi->channel - 1];
- /* get ie's */
- os_memcpy(r + 1, wbi + 1, wbi->ie_length);
- r->ie_len = wbi->ie_length;
-
- wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
- }
-
- wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
- "BSSes)",
- wsr->buflen, (unsigned long) ap_num);
-
- os_free(buf);
- return res;
- }
-
-static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct wpa_driver_broadcom_data *drv = priv;
- wlc_deauth_t wdt;
- wdt.val = reason_code;
- os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
- wdt.res = 0x7fff;
- return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
- sizeof(wdt));
-}
-
-static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct wpa_driver_broadcom_data *drv = priv;
- return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0);
-}
-
-static int
-wpa_driver_broadcom_associate(void *priv,
- struct wpa_driver_associate_params *params)
-{
- struct wpa_driver_broadcom_data *drv = priv;
- wlc_ssid_t s;
- int infra = 1;
- int auth = 0;
- int wsec = 4;
- int dummy;
- int wpa_auth;
- int ret;
-
- ret = wpa_driver_broadcom_set_drop_unencrypted(
- drv, params->drop_unencrypted);
-
- s.SSID_len = params->ssid_len;
- os_memcpy(s.SSID, params->ssid, params->ssid_len);
-
- switch (params->pairwise_suite) {
- case CIPHER_WEP40:
- case CIPHER_WEP104:
- wsec = 1;
- break;
-
- case CIPHER_TKIP:
- wsec = 2;
- break;
-
- case CIPHER_CCMP:
- wsec = 4;
- break;
-
- default:
- wsec = 0;
- break;
- }
-
- switch (params->key_mgmt_suite) {
- case KEY_MGMT_802_1X:
- wpa_auth = 1;
- break;
-
- case KEY_MGMT_PSK:
- wpa_auth = 2;
- break;
-
- default:
- wpa_auth = 255;
- break;
- }
-
- /* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
- * group_suite, key_mgmt_suite);
- * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
- * wl join uses wlc_sec_wep here, not wlc_set_wsec */
-
- if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
- sizeof(wpa_auth)) < 0 ||
- broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
- return -1;
-
- return ret;
-}
-
-const struct wpa_driver_ops wpa_driver_broadcom_ops = {
- .name = "broadcom",
- .desc = "Broadcom wl.o driver",
- .get_bssid = wpa_driver_broadcom_get_bssid,
- .get_ssid = wpa_driver_broadcom_get_ssid,
- .set_key = wpa_driver_broadcom_set_key,
- .init = wpa_driver_broadcom_init,
- .deinit = wpa_driver_broadcom_deinit,
- .set_countermeasures = wpa_driver_broadcom_set_countermeasures,
- .scan2 = wpa_driver_broadcom_scan,
- .get_scan_results2 = wpa_driver_broadcom_get_scan_results,
- .deauthenticate = wpa_driver_broadcom_deauthenticate,
- .disassociate = wpa_driver_broadcom_disassociate,
- .associate = wpa_driver_broadcom_associate,
-};
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
new file mode 100644
index 0000000..26ca8d6
--- /dev/null
+++ b/src/drivers/driver_common.c
@@ -0,0 +1,90 @@
+/*
+ * Common driver-related functions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include "utils/common.h"
+#include "driver.h"
+
+void wpa_scan_results_free(struct wpa_scan_results *res)
+{
+ size_t i;
+
+ if (res == NULL)
+ return;
+
+ for (i = 0; i < res->num; i++)
+ os_free(res->res[i]);
+ os_free(res->res);
+ os_free(res);
+}
+
+
+const char * event_to_string(enum wpa_event_type event)
+{
+#define E2S(n) case EVENT_ ## n: return #n
+ switch (event) {
+ E2S(ASSOC);
+ E2S(DISASSOC);
+ E2S(MICHAEL_MIC_FAILURE);
+ E2S(SCAN_RESULTS);
+ E2S(ASSOCINFO);
+ E2S(INTERFACE_STATUS);
+ E2S(PMKID_CANDIDATE);
+ E2S(STKSTART);
+ E2S(TDLS);
+ E2S(FT_RESPONSE);
+ E2S(IBSS_RSN_START);
+ E2S(AUTH);
+ E2S(DEAUTH);
+ E2S(ASSOC_REJECT);
+ E2S(AUTH_TIMED_OUT);
+ E2S(ASSOC_TIMED_OUT);
+ E2S(FT_RRB_RX);
+ E2S(WPS_BUTTON_PUSHED);
+ E2S(TX_STATUS);
+ E2S(RX_FROM_UNKNOWN);
+ E2S(RX_MGMT);
+ E2S(RX_ACTION);
+ E2S(REMAIN_ON_CHANNEL);
+ E2S(CANCEL_REMAIN_ON_CHANNEL);
+ E2S(MLME_RX);
+ E2S(RX_PROBE_REQ);
+ E2S(NEW_STA);
+ E2S(EAPOL_RX);
+ E2S(SIGNAL_CHANGE);
+ E2S(INTERFACE_ENABLED);
+ E2S(INTERFACE_DISABLED);
+ E2S(CHANNEL_LIST_CHANGED);
+ E2S(INTERFACE_UNAVAILABLE);
+ E2S(BEST_CHANNEL);
+ E2S(UNPROT_DEAUTH);
+ E2S(UNPROT_DISASSOC);
+ E2S(STATION_LOW_ACK);
+ E2S(P2P_DEV_FOUND);
+ E2S(P2P_GO_NEG_REQ_RX);
+ E2S(P2P_GO_NEG_COMPLETED);
+ E2S(P2P_PROV_DISC_REQUEST);
+ E2S(P2P_PROV_DISC_RESPONSE);
+ E2S(P2P_SD_REQUEST);
+ E2S(P2P_SD_RESPONSE);
+ E2S(IBSS_PEER_LOST);
+ E2S(DRIVER_GTK_REKEY);
+ E2S(SCHED_SCAN_STOPPED);
+ E2S(DRIVER_CLIENT_POLL_OK);
+ E2S(EAPOL_TX_STATUS);
+ }
+
+ return "UNKNOWN";
+#undef E2S
+}
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index e855c1b..8fc0efd 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -15,7 +15,7 @@
#include "includes.h"
#include <sys/ioctl.h>
-#include "wireless_copy.h"
+#include "linux_wext.h"
#include "common.h"
#include "driver.h"
#include "driver_wext.h"
@@ -23,8 +23,6 @@
#include "driver_hostap.h"
-#ifdef HOSTAPD
-
#include <net/if_arp.h>
#include <netpacket/packet.h>
@@ -32,6 +30,7 @@
#include "netlink.h"
#include "linux_ioctl.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
/* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
@@ -84,8 +83,8 @@ static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len,
sa = hdr->addr2;
os_memset(&event, 0, sizeof(event));
- event.rx_from_unknown.frame = buf;
- event.rx_from_unknown.len = len;
+ event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+ event.rx_from_unknown.addr = sa;
wpa_supplicant_event(drv->hapd, EVENT_RX_FROM_UNKNOWN, &event);
pos = (u8 *) (hdr + 1);
@@ -148,7 +147,6 @@ static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len)
{
struct ieee80211_hdr *hdr;
u16 fc, extra_len, type, stype;
- unsigned char *extra = NULL;
size_t data_len = len;
int ver;
union wpa_event_data event;
@@ -185,7 +183,6 @@ static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len)
return;
}
len -= extra_len + 2;
- extra = buf + len;
} else if (ver == 1 || ver == 2) {
handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0);
return;
@@ -273,7 +270,7 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
}
-static int hostap_send_mlme(void *priv, const u8 *msg, size_t len)
+static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack)
{
struct hostap_driver_data *drv = priv;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -322,7 +319,7 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
pos += 2;
memcpy(pos, data, data_len);
- res = hostap_send_mlme(drv, (u8 *) hdr, len);
+ res = hostap_send_mlme(drv, (u8 *) hdr, len, 0);
if (res < 0) {
wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
"failed: %d (%s)",
@@ -1054,7 +1051,26 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth));
+ sizeof(mgmt.u.deauth), 0);
+}
+
+
+static int hostap_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+ struct hostap_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.freq.m = freq->channel;
+ iwr.u.freq.e = 0;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+ perror("ioctl[SIOCSIWFREQ]");
+ return -1;
+ }
+
+ return 0;
}
@@ -1072,7 +1088,7 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.disassoc));
+ sizeof(mgmt.u.disassoc), 0);
}
@@ -1126,492 +1142,38 @@ static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv,
return mode;
}
-#else /* HOSTAPD */
-
-struct wpa_driver_hostap_data {
- void *wext; /* private data for driver_wext */
- void *ctx;
- char ifname[IFNAMSIZ + 1];
- int sock;
- int current_mode; /* infra/adhoc */
-};
-
-
-static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg);
-
-
-static int hostapd_ioctl(struct wpa_driver_hostap_data *drv,
- struct prism2_hostapd_param *param,
- int len, int show_err)
-{
- struct iwreq iwr;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.data.pointer = (caddr_t) param;
- iwr.u.data.length = len;
-
- if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
- int ret = errno;
- if (show_err)
- perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
- return ret;
- }
-
- return 0;
-}
-
-
-static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv,
- const u8 *wpa_ie, size_t wpa_ie_len)
-{
- struct prism2_hostapd_param *param;
- int res;
- size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
- if (blen < sizeof(*param))
- blen = sizeof(*param);
-
- param = os_zalloc(blen);
- if (param == NULL)
- return -1;
-
- param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
- param->u.generic_elem.len = wpa_ie_len;
- os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
- res = hostapd_ioctl(drv, param, blen, 1);
-
- os_free(param);
-
- return res;
-}
-
-
-static int prism2param(struct wpa_driver_hostap_data *drv, int param,
- int value)
-{
- struct iwreq iwr;
- int *i, ret = 0;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- i = (int *) iwr.u.name;
- *i++ = param;
- *i++ = value;
-
- if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
- perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
- ret = -1;
- }
- return ret;
-}
-
-
-static int wpa_driver_hostap_set_wpa(void *priv, int enabled)
-{
- struct wpa_driver_hostap_data *drv = priv;
- int ret = 0;
-
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-
- if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0)
- ret = -1;
- if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0)
- ret = -1;
- if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0)
- ret = -1;
-
- return ret;
-}
-
-
-static void show_set_key_error(struct prism2_hostapd_param *param)
-{
- switch (param->u.crypt.err) {
- case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
- wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
- param->u.crypt.alg);
- wpa_printf(MSG_INFO, "You may need to load kernel module to "
- "register that algorithm.");
- wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
- "WEP.");
- break;
- case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
- wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
- MAC2STR(param->sta_addr));
- break;
- case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
- wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
- break;
- case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
- wpa_printf(MSG_INFO, "Key setting failed.");
- break;
- case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
- wpa_printf(MSG_INFO, "TX key index setting failed.");
- break;
- case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
- wpa_printf(MSG_INFO, "Card configuration failed.");
- break;
- }
-}
-
-
-static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
- enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
- struct wpa_driver_hostap_data *drv = priv;
- struct prism2_hostapd_param *param;
- u8 *buf;
- size_t blen;
- int ret = 0;
- char *alg_name;
-
- switch (alg) {
- case WPA_ALG_NONE:
- alg_name = "none";
- break;
- case WPA_ALG_WEP:
- alg_name = "WEP";
- break;
- case WPA_ALG_TKIP:
- alg_name = "TKIP";
- break;
- case WPA_ALG_CCMP:
- alg_name = "CCMP";
- break;
- default:
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
- "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
- (unsigned long) seq_len, (unsigned long) key_len);
-
- if (seq_len > 8)
- return -2;
-
- blen = sizeof(*param) + key_len;
- buf = os_zalloc(blen);
- if (buf == NULL)
- return -1;
-
- param = (struct prism2_hostapd_param *) buf;
- param->cmd = PRISM2_SET_ENCRYPTION;
- /* TODO: In theory, STA in client mode can use five keys; four default
- * keys for receiving (with keyidx 0..3) and one individual key for
- * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
- * keyidx 0 is reserved for this unicast use and default keys can only
- * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
- * This should be fine for more or less all cases, but for completeness
- * sake, the driver could be enhanced to support the missing key. */
-#if 0
- if (addr == NULL)
- os_memset(param->sta_addr, 0xff, ETH_ALEN);
- else
- os_memcpy(param->sta_addr, addr, ETH_ALEN);
-#else
- os_memset(param->sta_addr, 0xff, ETH_ALEN);
-#endif
- os_strlcpy((char *) param->u.crypt.alg, alg_name,
- HOSTAP_CRYPT_ALG_NAME_LEN);
- param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
- param->u.crypt.idx = key_idx;
- if (seq)
- os_memcpy(param->u.crypt.seq, seq, seq_len);
- param->u.crypt.key_len = key_len;
- os_memcpy((u8 *) (param + 1), key, key_len);
-
- if (hostapd_ioctl(drv, param, blen, 1)) {
- wpa_printf(MSG_WARNING, "Failed to set encryption.");
- show_set_key_error(param);
- ret = -1;
- }
- os_free(buf);
-
- return ret;
-}
-
-
-static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled)
-{
- struct wpa_driver_hostap_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
- return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled);
-}
-
-
-static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv,
- int type)
-{
- struct iwreq iwr;
- int *i, ret = 0;
-
- wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type);
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- i = (int *) iwr.u.name;
- *i++ = type;
-
- if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) {
- perror("ioctl[PRISM2_IOCTL_RESET]");
- ret = -1;
- }
- return ret;
-}
-
-
-static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv,
- const u8 *addr, int cmd, int reason_code)
-{
- struct prism2_hostapd_param param;
- int ret;
-
- /* There does not seem to be a better way of deauthenticating or
- * disassociating with Prism2/2.5/3 than sending the management frame
- * and then resetting the Port0 to make sure both the AP and the STA
- * end up in disconnected state. */
- os_memset(&param, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_MLME;
- os_memcpy(param.sta_addr, addr, ETH_ALEN);
- param.u.mlme.cmd = cmd;
- param.u.mlme.reason_code = reason_code;
- ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
- if (ret == 0) {
- os_sleep(0, 100000);
- ret = wpa_driver_hostap_reset(drv, 2);
- }
- return ret;
-}
-
-
-static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct wpa_driver_hostap_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH,
- reason_code);
-}
-
-
-static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct wpa_driver_hostap_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC,
- reason_code);
-}
-
-static int
-wpa_driver_hostap_associate(void *priv,
- struct wpa_driver_associate_params *params)
+static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
+ const u8 *addr, int qos)
{
- struct wpa_driver_hostap_data *drv = priv;
- int ret = 0;
- int allow_unencrypted_eapol;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ struct ieee80211_hdr hdr;
- if (prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED,
- params->drop_unencrypted) < 0)
- ret = -1;
- if (wpa_driver_hostap_set_auth_alg(drv, params->auth_alg) < 0)
- ret = -1;
- if (params->mode != drv->current_mode) {
- /* At the moment, Host AP driver requires host_roaming=2 for
- * infrastructure mode and host_roaming=0 for adhoc. */
- if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING,
- params->mode == IEEE80211_MODE_IBSS ? 0 : 2) <
- 0) {
- wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming",
- __func__);
- }
- drv->current_mode = params->mode;
- }
-
- if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
- params->key_mgmt_suite != KEY_MGMT_NONE) < 0)
- ret = -1;
- if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie,
- params->wpa_ie_len) < 0)
- ret = -1;
- if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0)
- ret = -1;
- if (params->freq &&
- wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
- ret = -1;
- if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
- < 0)
- ret = -1;
- if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
- ret = -1;
+ os_memset(&hdr, 0, sizeof(hdr));
- /* Allow unencrypted EAPOL messages even if pairwise keys are set when
- * not using WPA. IEEE 802.1X specifies that these frames are not
- * encrypted, but WPA encrypts them when pairwise keys are in use. */
- if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
- params->key_mgmt_suite == KEY_MGMT_PSK)
- allow_unencrypted_eapol = 0;
- else
- allow_unencrypted_eapol = 1;
-
- if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X,
- allow_unencrypted_eapol) < 0) {
- wpa_printf(MSG_DEBUG, "hostap: Failed to configure "
- "ieee_802_1x param");
- /* Ignore this error.. driver_hostap.c can also be used with
- * other drivers that do not support this prism2_param. */
- }
-
- return ret;
-}
-
-
-static int wpa_driver_hostap_scan(void *priv,
- struct wpa_driver_scan_params *params)
-{
- struct wpa_driver_hostap_data *drv = priv;
- struct prism2_hostapd_param param;
- int ret;
- const u8 *ssid = params->ssids[0].ssid;
- size_t ssid_len = params->ssids[0].ssid_len;
-
- if (ssid == NULL) {
- /* Use standard Linux Wireless Extensions ioctl if possible
- * because some drivers using hostap code in wpa_supplicant
- * might not support Host AP specific scan request (with SSID
- * info). */
- return wpa_driver_wext_scan(drv->wext, params);
- }
-
- if (ssid_len > 32)
- ssid_len = 32;
-
- os_memset(&param, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_SCAN_REQ;
- param.u.scan_req.ssid_len = ssid_len;
- os_memcpy(param.u.scan_req.ssid, ssid, ssid_len);
- ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
-
- /* Not all drivers generate "scan completed" wireless event, so try to
- * read results after a timeout. */
- eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
- drv->ctx);
- eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext,
- drv->ctx);
-
- return ret;
-}
-
-
-static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg)
-{
- struct wpa_driver_hostap_data *drv = priv;
- int algs = 0;
-
- if (auth_alg & WPA_AUTH_ALG_OPEN)
- algs |= 1;
- if (auth_alg & WPA_AUTH_ALG_SHARED)
- algs |= 2;
- if (auth_alg & WPA_AUTH_ALG_LEAP)
- algs |= 4;
- if (algs == 0)
- algs = 1; /* at least one algorithm should be set */
-
- return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs);
-}
-
-
-static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid)
-{
- struct wpa_driver_hostap_data *drv = priv;
- return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid)
-{
- struct wpa_driver_hostap_data *drv = priv;
- return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static struct wpa_scan_results * wpa_driver_hostap_get_scan_results(void *priv)
-{
- struct wpa_driver_hostap_data *drv = priv;
- return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_hostap_set_operstate(void *priv, int state)
-{
- struct wpa_driver_hostap_data *drv = priv;
- return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
-{
- struct wpa_driver_hostap_data *drv;
-
- drv = os_zalloc(sizeof(*drv));
- if (drv == NULL)
- return NULL;
- drv->wext = wpa_driver_wext_init(ctx, ifname);
- if (drv->wext == NULL) {
- os_free(drv);
- return NULL;
- }
-
- drv->ctx = ctx;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (drv->sock < 0) {
- perror("socket");
- wpa_driver_wext_deinit(drv->wext);
- os_free(drv);
- return NULL;
- }
-
- if (os_strncmp(ifname, "wlan", 4) == 0) {
- /*
- * Host AP driver may use both wlan# and wifi# interface in
- * wireless events.
- */
- char ifname2[IFNAMSIZ + 1];
- os_strlcpy(ifname2, ifname, sizeof(ifname2));
- os_memcpy(ifname2, "wifi", 4);
- wpa_driver_wext_alternative_ifindex(drv->wext, ifname2);
- }
-
- wpa_driver_hostap_set_wpa(drv, 1);
-
- return drv;
-}
+ /*
+ * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
+ * but it is apparently not retried so TX Exc events
+ * are not received for it.
+ * This is the reason the driver overrides the default
+ * handling.
+ */
+ hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA,
+ WLAN_FC_STYPE_DATA);
+ hdr.frame_control |=
+ host_to_le16(WLAN_FC_FROMDS);
+ os_memcpy(hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+ os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+ os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
-static void wpa_driver_hostap_deinit(void *priv)
-{
- struct wpa_driver_hostap_data *drv = priv;
- wpa_driver_hostap_set_wpa(drv, 0);
- wpa_driver_wext_deinit(drv->wext);
- close(drv->sock);
- os_free(drv);
+ hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0);
}
-#endif /* HOSTAPD */
-
const struct wpa_driver_ops wpa_driver_hostap_ops = {
.name = "hostap",
.desc = "Host AP driver (Intersil Prism2/2.5/3)",
.set_key = wpa_driver_hostap_set_key,
-#ifdef HOSTAPD
.hapd_init = hostap_init,
.hapd_deinit = hostap_driver_deinit,
.set_ieee8021x = hostap_set_ieee8021x,
@@ -1632,17 +1194,6 @@ const struct wpa_driver_ops wpa_driver_hostap_ops = {
.sta_clear_stats = hostap_sta_clear_stats,
.get_hw_feature_data = hostap_get_hw_feature_data,
.set_ap_wps_ie = hostap_set_ap_wps_ie,
-#else /* HOSTAPD */
- .get_bssid = wpa_driver_hostap_get_bssid,
- .get_ssid = wpa_driver_hostap_get_ssid,
- .set_countermeasures = wpa_driver_hostap_set_countermeasures,
- .scan2 = wpa_driver_hostap_scan,
- .get_scan_results2 = wpa_driver_hostap_get_scan_results,
- .deauthenticate = wpa_driver_hostap_deauthenticate,
- .disassociate = wpa_driver_hostap_disassociate,
- .associate = wpa_driver_hostap_associate,
- .init = wpa_driver_hostap_init,
- .deinit = wpa_driver_hostap_deinit,
- .set_operstate = wpa_driver_hostap_set_operstate,
-#endif /* HOSTAPD */
+ .set_freq = hostap_set_freq,
+ .poll_client = wpa_driver_hostap_poll_client,
};
diff --git a/src/drivers/driver_iphone.m b/src/drivers/driver_iphone.m
deleted file mode 100644
index 8213fda..0000000
--- a/src/drivers/driver_iphone.m
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#define Boolean __DummyBoolean
-#include <CoreFoundation/CoreFoundation.h>
-#undef Boolean
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-
-#include "MobileApple80211.h"
-
-struct wpa_driver_iphone_data {
- void *ctx;
- Apple80211Ref wireless_ctx;
- CFArrayRef scan_results;
- int ctrl_power;
-};
-
-
-static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
-{
- const void *res;
- CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
- kCFStringEncodingMacRoman);
- if (str == NULL)
- return NULL;
-
- res = CFDictionaryGetValue(dict, str);
- CFRelease(str);
- return res;
-}
-
-
-static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
-{
- struct wpa_driver_iphone_data *drv = priv;
- CFDataRef data;
- int err, len;
-
- err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
- &data);
- if (err != 0) {
- wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
- "failed: %d", err);
- return -1;
- }
-
- len = CFDataGetLength(data);
- if (len > 32) {
- CFRelease(data);
- return -1;
- }
- os_memcpy(ssid, CFDataGetBytePtr(data), len);
- CFRelease(data);
-
- return len;
-}
-
-
-static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
-{
- struct wpa_driver_iphone_data *drv = priv;
- CFStringRef data;
- int err;
- int a1, a2, a3, a4, a5, a6;
-
- err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
- &data);
- if (err != 0) {
- wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
- "failed: %d", err);
- return -1;
- }
-
- sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
- "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
- bssid[0] = a1;
- bssid[1] = a2;
- bssid[2] = a3;
- bssid[3] = a4;
- bssid[4] = a5;
- bssid[5] = a6;
-
- CFRelease(data);
-
- return 0;
-}
-
-
-static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
-{
- struct wpa_driver_iphone_data *drv = priv;
- int err;
-
- if (drv->scan_results) {
- CFRelease(drv->scan_results);
- drv->scan_results = NULL;
- }
-
- err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
- if (err) {
- wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
- err);
- return -1;
- }
-
- eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
- drv->ctx);
- return 0;
-}
-
-
-static int wpa_driver_iphone_get_scan_results(void *priv,
- struct wpa_scan_result *results,
- size_t max_size)
-{
- struct wpa_driver_iphone_data *drv = priv;
- size_t i, num;
-
- if (drv->scan_results == NULL)
- return 0;
-
- num = CFArrayGetCount(drv->scan_results);
- if (num > max_size)
- num = max_size;
- os_memset(results, 0, num * sizeof(struct wpa_scan_result));
-
- for (i = 0; i < num; i++) {
- struct wpa_scan_result *res = &results[i];
- CFDictionaryRef dict =
- CFArrayGetValueAtIndex(drv->scan_results, i);
- CFDataRef data;
- CFStringRef str;
- CFNumberRef num;
- int val;
-
- data = cfdict_get_key_str(dict, "SSID");
- if (data) {
- res->ssid_len = CFDataGetLength(data);
- if (res->ssid_len > 32)
- res->ssid_len = 32;
- os_memcpy(res->ssid, CFDataGetBytePtr(data),
- res->ssid_len);
- }
-
- str = cfdict_get_key_str(dict, "BSSID");
- if (str) {
- int a1, a2, a3, a4, a5, a6;
- sscanf(CFStringGetCStringPtr(
- str, kCFStringEncodingMacRoman),
- "%x:%x:%x:%x:%x:%x",
- &a1, &a2, &a3, &a4, &a5, &a6);
- res->bssid[0] = a1;
- res->bssid[1] = a2;
- res->bssid[2] = a3;
- res->bssid[3] = a4;
- res->bssid[4] = a5;
- res->bssid[5] = a6;
- }
-
- num = cfdict_get_key_str(dict, "CAPABILITIES");
- if (num) {
- if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
- res->caps = val;
- }
-
- num = cfdict_get_key_str(dict, "CHANNEL");
- if (num) {
- if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
- res->freq = 2407 + val * 5;
- }
-
- num = cfdict_get_key_str(dict, "RSSI");
- if (num) {
- if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
- res->level = val;
- }
-
- num = cfdict_get_key_str(dict, "NOISE");
- if (num) {
- if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
- res->noise = val;
- }
-
- data = cfdict_get_key_str(dict, "IE");
- if (data) {
- u8 *ptr = (u8 *) CFDataGetBytePtr(data);
- int len = CFDataGetLength(data);
- u8 *pos = ptr, *end = ptr + len;
-
- while (pos + 2 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == WLAN_EID_RSN &&
- pos[1] <= SSID_MAX_WPA_IE_LEN) {
- os_memcpy(res->rsn_ie, pos,
- 2 + pos[1]);
- res->rsn_ie_len = 2 + pos[1];
- }
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
- pos[1] > 4 && pos[2] == 0x00 &&
- pos[3] == 0x50 && pos[4] == 0xf2 &&
- pos[5] == 0x01) {
- os_memcpy(res->wpa_ie, pos,
- 2 + pos[1]);
- res->wpa_ie_len = 2 + pos[1];
- }
-
- pos = pos + 2 + pos[1];
- }
- }
- }
-
- return num;
-}
-
-
-static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_driver_iphone_data *drv = eloop_ctx;
- u8 bssid[ETH_ALEN];
-
- if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
- eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
- drv, drv->ctx);
- return;
- }
-
- wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
-}
-
-
-static int wpa_driver_iphone_associate(
- void *priv, struct wpa_driver_associate_params *params)
-{
- struct wpa_driver_iphone_data *drv = priv;
- int i, num, err;
- size_t ssid_len;
- CFDictionaryRef bss = NULL;
-
- /*
- * TODO: Consider generating parameters instead of just using an entry
- * from scan results in order to support ap_scan=2.
- */
-
- if (drv->scan_results == NULL) {
- wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
- "associate");
- return -1;
- }
-
- num = CFArrayGetCount(drv->scan_results);
-
- for (i = 0; i < num; i++) {
- CFDictionaryRef dict =
- CFArrayGetValueAtIndex(drv->scan_results, i);
- CFDataRef data;
-
- data = cfdict_get_key_str(dict, "SSID");
- if (data == NULL)
- continue;
-
- ssid_len = CFDataGetLength(data);
- if (ssid_len != params->ssid_len ||
- os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
- != 0)
- continue;
-
- bss = dict;
- break;
- }
-
- if (bss == NULL) {
- wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
- "results - cannot associate");
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
- "from scan results");
-
- err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
- if (err) {
- wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
- "%d", err);
- return -1;
- }
-
- /*
- * Driver is actually already associated; report association from an
- * eloop callback.
- */
- eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
- eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
- drv->ctx);
-
- return 0;
-}
-
-
-static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx, const u8 *seq,
- size_t seq_len, const u8 *key,
- size_t key_len)
-{
- /*
- * TODO: Need to either support configuring PMK for 4-way handshake or
- * PTK for TKIP/CCMP.
- */
- return -1;
-}
-
-
-static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
- os_memset(capa, 0, sizeof(*capa));
-
- capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
- capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
- WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
- capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
- WPA_DRIVER_AUTH_LEAP;
- capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
-
- return 0;
-}
-
-
-static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
-{
- struct wpa_driver_iphone_data *drv;
- int err;
- char power;
- CFStringRef name;
- CFDictionaryRef dict;
-
- drv = os_zalloc(sizeof(*drv));
- if (drv == NULL)
- return NULL;
- drv->ctx = ctx;
- err = Apple80211Open(&drv->wireless_ctx);
- if (err) {
- wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
- err);
- os_free(drv);
- return NULL;
- }
-
- name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
- kCFStringEncodingISOLatin1);
- if (name == NULL) {
- wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
- Apple80211Close(drv->wireless_ctx);
- os_free(drv);
- return NULL;
- }
-
- err = Apple80211BindToInterface(drv->wireless_ctx, name);
- CFRelease(name);
-
- if (err) {
- wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
- "failed: %d", err);
- Apple80211Close(drv->wireless_ctx);
- os_free(drv);
- return NULL;
- }
-
- err = Apple80211GetPower(drv->wireless_ctx, &power);
- if (err)
- wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
- err);
-
- wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
-
- if (!power) {
- drv->ctrl_power = 1;
- err = Apple80211SetPower(drv->wireless_ctx, 1);
- if (err) {
- wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
- "failed: %d", err);
- Apple80211Close(drv->wireless_ctx);
- os_free(drv);
- return NULL;
- }
- }
-
- err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
- if (err == 0) {
- CFShow(dict);
- CFRelease(dict);
- } else {
- printf("Apple80211GetInfoCopy: %d\n", err);
- }
-
- return drv;
-}
-
-
-static void wpa_driver_iphone_deinit(void *priv)
-{
- struct wpa_driver_iphone_data *drv = priv;
- int err;
-
- eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
- eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
-
- if (drv->ctrl_power) {
- wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
- err = Apple80211SetPower(drv->wireless_ctx, 0);
- if (err) {
- wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
- "failed: %d", err);
- }
- }
-
- err = Apple80211Close(drv->wireless_ctx);
- if (err) {
- wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
- err);
- }
-
- if (drv->scan_results)
- CFRelease(drv->scan_results);
-
- os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_iphone_ops = {
- .name = "iphone",
- .desc = "iPhone/iPod touch Apple80211 driver",
- .get_ssid = wpa_driver_iphone_get_ssid,
- .get_bssid = wpa_driver_iphone_get_bssid,
- .init = wpa_driver_iphone_init,
- .deinit = wpa_driver_iphone_deinit,
- .scan = wpa_driver_iphone_scan,
- .get_scan_results = wpa_driver_iphone_get_scan_results,
- .associate = wpa_driver_iphone_associate,
- .set_key = wpa_driver_iphone_set_key,
- .get_capa = wpa_driver_iphone_get_capa,
-};
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
index 630fbf4..edb086f 100644
--- a/src/drivers/driver_madwifi.c
+++ b/src/drivers/driver_madwifi.c
@@ -27,7 +27,7 @@
#include "driver_wext.h"
#include "eloop.h"
#include "common/ieee802_11_defs.h"
-#include "wireless_copy.h"
+#include "linux_wext.h"
/*
* Avoid conflicts with wpa_supplicant definitions by undefining a definition.
@@ -71,8 +71,6 @@
#define WPA_KEY_RSC_LEN 8
-#ifdef HOSTAPD
-
#include "priv_netlink.h"
#include "netlink.h"
#include "linux_ioctl.h"
@@ -734,6 +732,8 @@ static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
os_memset(&event, 0, sizeof(event));
event.rx_probe_req.sa = mgmt->sa;
+ event.rx_probe_req.da = mgmt->da;
+ event.rx_probe_req.bssid = mgmt->bssid;
event.rx_probe_req.ie = mgmt->u.probe_req.variable;
event.rx_probe_req.ie_len =
len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
@@ -804,6 +804,24 @@ madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
#define madwifi_set_ap_wps_ie NULL
#endif /* CONFIG_WPS */
+static int madwifi_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.freq.m = freq->channel;
+ iwr.u.freq.e = 0;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+ perror("ioctl[SIOCSIWFREQ]");
+ return -1;
+ }
+
+ return 0;
+}
+
static void
madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
{
@@ -1274,554 +1292,11 @@ madwifi_commit(void *priv)
return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
}
-#else /* HOSTAPD */
-
-struct wpa_driver_madwifi_data {
- void *wext; /* private data for driver_wext */
- void *ctx;
- char ifname[IFNAMSIZ + 1];
- int sock;
-};
-
-static int wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg);
-static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
- size_t ies_len);
-
-
-static int
-set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
- int show_err)
-{
- struct iwreq iwr;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- if (len < IFNAMSIZ &&
- op != IEEE80211_IOCTL_SET_APPIEBUF) {
- /*
- * Argument data fits inline; put it there.
- */
- os_memcpy(iwr.u.name, data, len);
- } else {
- /*
- * Argument data too big for inline transfer; setup a
- * parameter block instead; the kernel will transfer
- * the data for the driver.
- */
- iwr.u.data.pointer = data;
- iwr.u.data.length = len;
- }
-
- if (ioctl(drv->sock, op, &iwr) < 0) {
- if (show_err) {
-#ifdef MADWIFI_NG
- int first = IEEE80211_IOCTL_SETPARAM;
- int last = IEEE80211_IOCTL_KICKMAC;
- static const char *opnames[] = {
- "ioctl[IEEE80211_IOCTL_SETPARAM]",
- "ioctl[IEEE80211_IOCTL_GETPARAM]",
- "ioctl[IEEE80211_IOCTL_SETMODE]",
- "ioctl[IEEE80211_IOCTL_GETMODE]",
- "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
- "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
- "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
- "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
- "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
- NULL,
- "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
- "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
- NULL,
- "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
- "ioctl[IEEE80211_IOCTL_SETOPTIE]",
- "ioctl[IEEE80211_IOCTL_GETOPTIE]",
- "ioctl[IEEE80211_IOCTL_SETMLME]",
- NULL,
- "ioctl[IEEE80211_IOCTL_SETKEY]",
- NULL,
- "ioctl[IEEE80211_IOCTL_DELKEY]",
- NULL,
- "ioctl[IEEE80211_IOCTL_ADDMAC]",
- NULL,
- "ioctl[IEEE80211_IOCTL_DELMAC]",
- NULL,
- "ioctl[IEEE80211_IOCTL_WDSMAC]",
- NULL,
- "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
- NULL,
- "ioctl[IEEE80211_IOCTL_KICKMAC]",
- };
-#else /* MADWIFI_NG */
- int first = IEEE80211_IOCTL_SETPARAM;
- int last = IEEE80211_IOCTL_CHANLIST;
- static const char *opnames[] = {
- "ioctl[IEEE80211_IOCTL_SETPARAM]",
- "ioctl[IEEE80211_IOCTL_GETPARAM]",
- "ioctl[IEEE80211_IOCTL_SETKEY]",
- "ioctl[IEEE80211_IOCTL_GETKEY]",
- "ioctl[IEEE80211_IOCTL_DELKEY]",
- NULL,
- "ioctl[IEEE80211_IOCTL_SETMLME]",
- NULL,
- "ioctl[IEEE80211_IOCTL_SETOPTIE]",
- "ioctl[IEEE80211_IOCTL_GETOPTIE]",
- "ioctl[IEEE80211_IOCTL_ADDMAC]",
- NULL,
- "ioctl[IEEE80211_IOCTL_DELMAC]",
- NULL,
- "ioctl[IEEE80211_IOCTL_CHANLIST]",
- };
-#endif /* MADWIFI_NG */
- int idx = op - first;
- if (first <= op && op <= last &&
- idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
- && opnames[idx])
- perror(opnames[idx]);
- else
- perror("ioctl[unknown???]");
- }
- return -1;
- }
- return 0;
-}
-
-static int
-set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
- int show_err)
-{
- struct iwreq iwr;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.mode = op;
- os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
-
- if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
- if (show_err)
- perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
- return -1;
- }
- return 0;
-}
-
-static int
-wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
- const u8 *wpa_ie, size_t wpa_ie_len)
-{
- struct iwreq iwr;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- /* NB: SETOPTIE is not fixed-size so must not be inlined */
- iwr.u.data.pointer = (void *) wpa_ie;
- iwr.u.data.length = wpa_ie_len;
-
- if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
- perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
- return -1;
- }
- return 0;
-}
-
-static int
-wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
- const u8 *addr)
-{
- struct ieee80211req_del_key wk;
-
- wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
- os_memset(&wk, 0, sizeof(wk));
- wk.idk_keyix = key_idx;
- if (addr != NULL)
- os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
-
- return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
-}
-
-static int
-wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- struct ieee80211req_key wk;
- char *alg_name;
- u_int8_t cipher;
-
- if (alg == WPA_ALG_NONE)
- return wpa_driver_madwifi_del_key(drv, key_idx, addr);
-
- switch (alg) {
- case WPA_ALG_WEP:
- if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
- ETH_ALEN) == 0) {
- /*
- * madwifi did not seem to like static WEP key
- * configuration with IEEE80211_IOCTL_SETKEY, so use
- * Linux wireless extensions ioctl for this.
- */
- return wpa_driver_wext_set_key(ifname, drv->wext, alg,
- addr, key_idx, set_tx,
- seq, seq_len,
- key, key_len);
- }
- alg_name = "WEP";
- cipher = IEEE80211_CIPHER_WEP;
- break;
- case WPA_ALG_TKIP:
- alg_name = "TKIP";
- cipher = IEEE80211_CIPHER_TKIP;
- break;
- case WPA_ALG_CCMP:
- alg_name = "CCMP";
- cipher = IEEE80211_CIPHER_AES_CCM;
- break;
- default:
- wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
- __FUNCTION__, alg);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
- "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
- (unsigned long) seq_len, (unsigned long) key_len);
-
- if (seq_len > sizeof(u_int64_t)) {
- wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
- __FUNCTION__, (unsigned long) seq_len);
- return -2;
- }
- if (key_len > sizeof(wk.ik_keydata)) {
- wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
- __FUNCTION__, (unsigned long) key_len);
- return -3;
- }
-
- os_memset(&wk, 0, sizeof(wk));
- wk.ik_type = cipher;
- wk.ik_flags = IEEE80211_KEY_RECV;
- if (addr == NULL ||
- os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
- wk.ik_flags |= IEEE80211_KEY_GROUP;
- if (set_tx) {
- wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
- os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
- } else
- os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
- wk.ik_keyix = key_idx;
- wk.ik_keylen = key_len;
-#ifdef WORDS_BIGENDIAN
- if (seq) {
- size_t i;
- u8 tmp[WPA_KEY_RSC_LEN];
- os_memset(tmp, 0, sizeof(tmp));
- for (i = 0; i < seq_len; i++)
- tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
- os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
- }
-#else /* WORDS_BIGENDIAN */
- if (seq)
- os_memcpy(&wk.ik_keyrsc, seq, seq_len);
-#endif /* WORDS_BIGENDIAN */
- os_memcpy(wk.ik_keydata, key, key_len);
-
- return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
-}
-
-static int
-wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
- return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
-}
-
-static int
-wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- struct ieee80211req_mlme mlme;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- mlme.im_op = IEEE80211_MLME_DEAUTH;
- mlme.im_reason = reason_code;
- os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
- return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
-}
-
-static int
-wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- struct ieee80211req_mlme mlme;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- mlme.im_op = IEEE80211_MLME_DISASSOC;
- mlme.im_reason = reason_code;
- os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
- return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
-}
-
-static int
-wpa_driver_madwifi_associate(void *priv,
- struct wpa_driver_associate_params *params)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- struct ieee80211req_mlme mlme;
- int ret = 0, privacy = 1;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- if (set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED,
- params->drop_unencrypted, 1) < 0)
- ret = -1;
- if (wpa_driver_madwifi_set_auth_alg(drv, params->auth_alg) < 0)
- ret = -1;
-
- /*
- * NB: Don't need to set the freq or cipher-related state as
- * this is implied by the bssid which is used to locate
- * the scanned node state which holds it. The ssid is
- * needed to disambiguate an AP that broadcasts multiple
- * ssid's but uses the same bssid.
- */
- /* XXX error handling is wrong but unclear what to do... */
- if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
- params->wpa_ie_len) < 0)
- ret = -1;
-
- if (params->pairwise_suite == CIPHER_NONE &&
- params->group_suite == CIPHER_NONE &&
- params->key_mgmt_suite == KEY_MGMT_NONE &&
- params->wpa_ie_len == 0)
- privacy = 0;
-
- if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
- ret = -1;
-
- if (params->wpa_ie_len &&
- set80211param(drv, IEEE80211_PARAM_WPA,
- params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
- ret = -1;
-
- if (params->bssid == NULL) {
- /* ap_scan=2 mode - driver takes care of AP selection and
- * roaming */
- /* FIX: this does not seem to work; would probably need to
- * change something in the driver */
- if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
- ret = -1;
-
- if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
- params->ssid_len) < 0)
- ret = -1;
- } else {
- if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
- ret = -1;
- if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
- params->ssid_len) < 0)
- ret = -1;
- os_memset(&mlme, 0, sizeof(mlme));
- mlme.im_op = IEEE80211_MLME_ASSOC;
- os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
- if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
- sizeof(mlme), 1) < 0) {
- wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
- __func__);
- ret = -1;
- }
- }
-
- return ret;
-}
-
-static int
-wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- int authmode;
-
- if ((auth_alg & WPA_AUTH_ALG_OPEN) &&
- (auth_alg & WPA_AUTH_ALG_SHARED))
- authmode = IEEE80211_AUTH_AUTO;
- else if (auth_alg & WPA_AUTH_ALG_SHARED)
- authmode = IEEE80211_AUTH_SHARED;
- else
- authmode = IEEE80211_AUTH_OPEN;
-
- return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
-}
-
-static int
-wpa_driver_madwifi_scan(void *priv, struct wpa_driver_scan_params *params)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
- const u8 *ssid = params->ssids[0].ssid;
- size_t ssid_len = params->ssids[0].ssid_len;
-
- wpa_driver_madwifi_set_probe_req_ie(drv, params->extra_ies,
- params->extra_ies_len);
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
- /* set desired ssid before scan */
- /* FIX: scan should not break the current association, so using
- * set_ssid may not be the best way of doing this.. */
- if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
- ret = -1;
-
- if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
- perror("ioctl[SIOCSIWSCAN]");
- ret = -1;
- }
-
- /*
- * madwifi delivers a scan complete event so no need to poll, but
- * register a backup timeout anyway to make sure that we recover even
- * if the driver does not send this event for any reason. This timeout
- * will only be used if the event is not delivered (event handler will
- * cancel the timeout).
- */
- eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
- drv->ctx);
- eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
- drv->ctx);
-
- return ret;
-}
-
-static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static struct wpa_scan_results *
-wpa_driver_madwifi_get_scan_results(void *priv)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_madwifi_set_operstate(void *priv, int state)
-{
- struct wpa_driver_madwifi_data *drv = priv;
- return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
- size_t ies_len)
-{
- struct ieee80211req_getset_appiebuf *probe_req_ie;
- int ret;
-
- probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
- if (probe_req_ie == NULL)
- return -1;
-
- probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
- probe_req_ie->app_buflen = ies_len;
- os_memcpy(probe_req_ie->app_buf, ies, ies_len);
-
- ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
- sizeof(struct ieee80211req_getset_appiebuf) +
- ies_len, 1);
-
- os_free(probe_req_ie);
-
- return ret;
-}
-
-
-static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
-{
- struct wpa_driver_madwifi_data *drv;
-
- drv = os_zalloc(sizeof(*drv));
- if (drv == NULL)
- return NULL;
- drv->wext = wpa_driver_wext_init(ctx, ifname);
- if (drv->wext == NULL)
- goto fail;
-
- drv->ctx = ctx;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (drv->sock < 0)
- goto fail2;
-
- if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
- wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
- "roaming", __FUNCTION__);
- goto fail3;
- }
-
- if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
- wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
- __FUNCTION__);
- goto fail3;
- }
-
- return drv;
-
-fail3:
- close(drv->sock);
-fail2:
- wpa_driver_wext_deinit(drv->wext);
-fail:
- os_free(drv);
- return NULL;
-}
-
-
-static void wpa_driver_madwifi_deinit(void *priv)
-{
- struct wpa_driver_madwifi_data *drv = priv;
-
- if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
- wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
- __FUNCTION__);
- }
- if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
- wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
- "roaming", __FUNCTION__);
- }
- if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
- wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
- "flag", __FUNCTION__);
- }
- if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
- wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
- __FUNCTION__);
- }
-
- wpa_driver_wext_deinit(drv->wext);
-
- close(drv->sock);
- os_free(drv);
-}
-
-#endif /* HOSTAPD */
-
const struct wpa_driver_ops wpa_driver_madwifi_ops = {
.name = "madwifi",
.desc = "MADWIFI 802.11 support (Atheros, etc.)",
.set_key = wpa_driver_madwifi_set_key,
-#ifdef HOSTAPD
.hapd_init = madwifi_init,
.hapd_deinit = madwifi_deinit,
.set_ieee8021x = madwifi_set_ieee8021x,
@@ -1840,17 +1315,5 @@ const struct wpa_driver_ops wpa_driver_madwifi_ops = {
.sta_clear_stats = madwifi_sta_clear_stats,
.commit = madwifi_commit,
.set_ap_wps_ie = madwifi_set_ap_wps_ie,
-#else /* HOSTAPD */
- .get_bssid = wpa_driver_madwifi_get_bssid,
- .get_ssid = wpa_driver_madwifi_get_ssid,
- .init = wpa_driver_madwifi_init,
- .deinit = wpa_driver_madwifi_deinit,
- .set_countermeasures = wpa_driver_madwifi_set_countermeasures,
- .scan2 = wpa_driver_madwifi_scan,
- .get_scan_results2 = wpa_driver_madwifi_get_scan_results,
- .deauthenticate = wpa_driver_madwifi_deauthenticate,
- .disassociate = wpa_driver_madwifi_disassociate,
- .associate = wpa_driver_madwifi_associate,
- .set_operstate = wpa_driver_madwifi_set_operstate,
-#endif /* HOSTAPD */
+ .set_freq = madwifi_set_freq,
};
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index aeb7304..dbe9a28 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -3213,119 +3213,33 @@ wpa_driver_ndis_get_interfaces(void *global_priv)
}
-const struct wpa_driver_ops wpa_driver_ndis_ops = {
- "ndis",
- "Windows NDIS driver",
- wpa_driver_ndis_get_bssid,
- wpa_driver_ndis_get_ssid,
- wpa_driver_ndis_set_key,
- wpa_driver_ndis_init,
- wpa_driver_ndis_deinit,
- NULL /* set_param */,
- NULL /* set_countermeasures */,
- wpa_driver_ndis_deauthenticate,
- wpa_driver_ndis_disassociate,
- wpa_driver_ndis_associate,
- wpa_driver_ndis_add_pmkid,
- wpa_driver_ndis_remove_pmkid,
- wpa_driver_ndis_flush_pmkid,
- wpa_driver_ndis_get_capa,
- wpa_driver_ndis_poll,
- wpa_driver_ndis_get_ifname,
- wpa_driver_ndis_get_mac_addr,
- NULL /* send_eapol */,
- NULL /* set_operstate */,
- NULL /* mlme_setprotection */,
- NULL /* get_hw_feature_data */,
- NULL /* set_channel */,
- NULL /* set_ssid */,
- NULL /* set_bssid */,
- NULL /* send_mlme */,
- NULL /* mlme_add_sta */,
- NULL /* mlme_remove_sta */,
- NULL /* update_ft_ies */,
- NULL /* send_ft_action */,
- wpa_driver_ndis_get_scan_results,
- NULL /* set_country */,
- NULL /* global_init */,
- NULL /* global_deinit */,
- NULL /* init2 */,
- wpa_driver_ndis_get_interfaces,
- wpa_driver_ndis_scan,
- NULL /* authenticate */,
- NULL /* set_beacon */,
- NULL /* hapd_init */,
- NULL /* hapd_deinit */,
- NULL /* set_ieee8021x */,
- NULL /* set_privacy */,
- NULL /* get_seqnum */,
- NULL /* flush */,
- NULL /* set_generic_elem */,
- NULL /* read_sta_data */,
- NULL /* hapd_send_eapol */,
- NULL /* sta_deauth */,
- NULL /* sta_disassoc */,
- NULL /* sta_remove */,
- NULL /* hapd_get_ssid */,
- NULL /* hapd_set_ssid */,
- NULL /* hapd_set_countermeasures */,
- NULL /* sta_add */,
- NULL /* get_inact_sec */,
- NULL /* sta_clear_stats */,
- NULL /* set_freq */,
- NULL /* set_rts */,
- NULL /* set_frag */,
- NULL /* sta_set_flags */,
- NULL /* set_rate_sets */,
- NULL /* set_cts_protect */,
- NULL /* set_preamble */,
- NULL /* set_short_slot_time */,
- NULL /* set_tx_queue_params */,
- NULL /* valid_bss_mask */,
- NULL /* if_add */,
- NULL /* if_remove */,
- NULL /* set_sta_vlan */,
- NULL /* commit */,
- NULL /* send_ether */,
- NULL /* set_radius_acl_auth */,
- NULL /* set_radius_acl_expire */,
- NULL /* set_ht_params */,
- NULL /* set_ap_wps_ie */,
- NULL /* set_supp_port */,
- NULL /* set_wds_sta */,
- NULL /* send_action */,
- NULL /* send_action_cancel_wait */,
- NULL /* remain_on_channel */,
- NULL /* cancel_remain_on_channel */,
- NULL /* probe_req_report */,
- NULL /* disable_11b_rates */,
- NULL /* deinit_ap */,
- NULL /* suspend */,
- NULL /* resume */,
- NULL /* signal_monitor */,
- NULL /* send_frame */,
- NULL /* shared_freq */,
- NULL /* get_noa */,
- NULL /* set_noa */,
- NULL /* set_p2p_powersave */,
- NULL /* ampdu */,
- NULL /* set_intra_bss */,
- NULL /* get_radio_name */,
- NULL /* p2p_find */,
- NULL /* p2p_stop_find */,
- NULL /* p2p_listen */,
- NULL /* p2p_connect */,
- NULL /* wps_success_cb */,
- NULL /* p2p_group_formation_failed */,
- NULL /* p2p_set_params */,
- NULL /* p2p_prov_disc_req */,
- NULL /* p2p_sd_request */,
- NULL /* p2p_sd_cancel_request */,
- NULL /* p2p_sd_response */,
- NULL /* p2p_service_update */,
- NULL /* p2p_reject */,
- NULL /* p2p_invite */,
- NULL /* send_tdls_mgmt */,
- NULL /* tdls_oper */,
- NULL /* signal_poll */
-};
+static const char *ndis_drv_name = "ndis";
+static const char *ndis_drv_desc = "Windows NDIS driver";
+
+struct wpa_driver_ops wpa_driver_ndis_ops;
+
+void driver_ndis_init_ops(void)
+{
+ os_memset(&wpa_driver_ndis_ops, 0, sizeof(wpa_driver_ndis_ops));
+ wpa_driver_ndis_ops.name = ndis_drv_name;
+ wpa_driver_ndis_ops.desc = ndis_drv_desc;
+ wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid;
+ wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid;
+ wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key;
+ wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
+ wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
+ wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
+ wpa_driver_ndis_ops.disassociate = wpa_driver_ndis_disassociate;
+ wpa_driver_ndis_ops.associate = wpa_driver_ndis_associate;
+ wpa_driver_ndis_ops.add_pmkid = wpa_driver_ndis_add_pmkid;
+ wpa_driver_ndis_ops.remove_pmkid = wpa_driver_ndis_remove_pmkid;
+ wpa_driver_ndis_ops.flush_pmkid = wpa_driver_ndis_flush_pmkid;
+ wpa_driver_ndis_ops.get_capa = wpa_driver_ndis_get_capa;
+ wpa_driver_ndis_ops.poll = wpa_driver_ndis_poll;
+ wpa_driver_ndis_ops.get_ifname = wpa_driver_ndis_get_ifname;
+ wpa_driver_ndis_ops.get_mac_addr = wpa_driver_ndis_get_mac_addr;
+ wpa_driver_ndis_ops.get_scan_results2 =
+ wpa_driver_ndis_get_scan_results;
+ wpa_driver_ndis_ops.get_interfaces = wpa_driver_ndis_get_interfaces;
+ wpa_driver_ndis_ops.scan2 = wpa_driver_ndis_scan;
+}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index df309c5..a00f703 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -28,21 +28,47 @@
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
+#include <linux/errqueue.h>
#include "nl80211_copy.h"
#include "common.h"
#include "eloop.h"
#include "utils/list.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "l2_packet/l2_packet.h"
#include "netlink.h"
#include "linux_ioctl.h"
#include "radiotap.h"
#include "radiotap_iter.h"
#include "rfkill.h"
#include "driver.h"
-#if defined(ANDROID_BRCM_P2P_PATCH) && !defined(HOSTAPD)
+#if defined(ANDROID_P2P) && !defined(HOSTAPD)
#include "wpa_supplicant_i.h"
#endif
+#ifndef SO_WIFI_STATUS
+# if defined(__sparc__)
+# define SO_WIFI_STATUS 0x0025
+# elif defined(__parisc__)
+# define SO_WIFI_STATUS 0x4022
+# else
+# define SO_WIFI_STATUS 41
+# endif
+
+# define SCM_WIFI_STATUS SO_WIFI_STATUS
+#endif
+
+#ifndef SO_EE_ORIGIN_TXSTATUS
+#define SO_EE_ORIGIN_TXSTATUS 4
+#endif
+
+#ifndef PACKET_TX_TIMESTAMP
+#define PACKET_TX_TIMESTAMP 16
+#endif
+
+#ifdef ANDROID
+#include "android_drv.h"
+#endif /* ANDROID */
#ifdef CONFIG_LIBNL20
/* libnl 2.0 compatibility code */
#define nl_handle nl_sock
@@ -91,6 +117,37 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
#endif /* CONFIG_LIBNL20 */
+static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
+{
+ struct nl_handle *handle;
+
+ handle = nl80211_handle_alloc(cb);
+ if (handle == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks (%s)", dbg);
+ return NULL;
+ }
+
+ if (genl_connect(handle)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+ "netlink (%s)", dbg);
+ nl80211_handle_destroy(handle);
+ return NULL;
+ }
+
+ return handle;
+}
+
+
+static void nl_destroy_handles(struct nl_handle **handle)
+{
+ if (*handle == NULL)
+ return;
+ nl80211_handle_destroy(*handle);
+ *handle = NULL;
+}
+
+
#ifndef IFF_LOWER_UP
#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
#endif
@@ -107,8 +164,30 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
struct nl80211_global {
struct dl_list interfaces;
+ int if_add_ifindex;
+ struct netlink_data *netlink;
+ struct nl_cb *nl_cb;
+ struct nl_handle *nl;
+ int nl80211_id;
+ int ioctl_sock; /* socket for ioctl() use */
+
+ struct nl_handle *nl_event;
};
+struct nl80211_wiphy_data {
+ struct dl_list list;
+ struct dl_list bsss;
+ struct dl_list drvs;
+
+ struct nl_handle *nl_beacons;
+ struct nl_cb *nl_cb;
+
+ int wiphy_idx;
+};
+
+static void nl80211_global_deinit(void *priv);
+static void wpa_driver_nl80211_deinit(void *priv);
+
struct i802_bss {
struct wpa_driver_nl80211_data *drv;
struct i802_bss *next;
@@ -118,19 +197,28 @@ struct i802_bss {
unsigned int beacon_set:1;
unsigned int added_if_into_bridge:1;
unsigned int added_bridge:1;
+
+ u8 addr[ETH_ALEN];
+
+ int freq;
+
+ struct nl_handle *nl_preq, *nl_mgmt;
+ struct nl_cb *nl_cb;
+
+ struct nl80211_wiphy_data *wiphy_data;
+ struct dl_list wiphy_list;
};
struct wpa_driver_nl80211_data {
struct nl80211_global *global;
struct dl_list list;
- u8 addr[ETH_ALEN];
+ struct dl_list wiphy_list;
char phyname[32];
void *ctx;
- struct netlink_data *netlink;
- int ioctl_sock; /* socket for ioctl() use */
int ifindex;
int if_removed;
int if_disabled;
+ int ignore_if_down_event;
struct rfkill_data *rfkill;
struct wpa_driver_capa capa;
int has_capability;
@@ -139,42 +227,43 @@ struct wpa_driver_nl80211_data {
int scan_complete_events;
- struct nl_handle *nl_handle;
- struct nl_handle *nl_handle_event;
- struct nl_handle *nl_handle_preq;
- struct nl_cache *nl_cache;
- struct nl_cache *nl_cache_event;
- struct nl_cache *nl_cache_preq;
struct nl_cb *nl_cb;
- struct genl_family *nl80211;
u8 auth_bssid[ETH_ALEN];
u8 bssid[ETH_ALEN];
int associated;
u8 ssid[32];
size_t ssid_len;
- int nlmode;
- int ap_scan_as_station;
+ enum nl80211_iftype nlmode;
+ enum nl80211_iftype ap_scan_as_station;
unsigned int assoc_freq;
int monitor_sock;
int monitor_ifidx;
- int no_monitor_iface_capab;
- int disable_11b_rates;
+ int monitor_refcount;
+ unsigned int disabled_11b_rates:1;
unsigned int pending_remain_on_chan:1;
+ unsigned int in_interface_list:1;
+ unsigned int device_ap_sme:1;
+ unsigned int poll_command_supported:1;
+ unsigned int data_tx_status:1;
+ unsigned int scan_for_auth:1;
+ unsigned int retry_auth:1;
+ unsigned int use_monitor:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
unsigned int last_mgmt_freq;
- unsigned int ap_oper_freq;
struct wpa_driver_scan_filter *filter_ssids;
size_t num_filter_ssids;
struct i802_bss first_bss;
+ int eapol_tx_sock;
+
#ifdef HOSTAPD
int eapol_sock; /* socket for EAPOL frames */
@@ -185,12 +274,27 @@ struct wpa_driver_nl80211_data {
int last_freq;
int last_freq_ht;
#endif /* HOSTAPD */
+
+ /* From failed authentication command */
+ int auth_freq;
+ u8 auth_bssid_[ETH_ALEN];
+ u8 auth_ssid[32];
+ size_t auth_ssid_len;
+ int auth_alg;
+ u8 *auth_ie;
+ size_t auth_ie_len;
+ u8 auth_wep_key[4][16];
+ size_t auth_wep_key_len[4];
+ int auth_wep_tx_keyidx;
+ int auth_local_state_change;
+ int auth_p2p;
};
static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
void *timeout_ctx);
-static int wpa_driver_nl80211_set_mode(void *priv, int mode);
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+ enum nl80211_iftype nlmode);
static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
@@ -198,22 +302,28 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
int local_state_change);
static void nl80211_remove_monitor_interface(
struct wpa_driver_nl80211_data *drv);
-static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
+static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait,
- const u8 *buf, size_t buf_len, u64 *cookie);
+ const u8 *buf, size_t buf_len, u64 *cookie,
+ int no_cck, int no_ack, int offchanok);
static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID
+static int android_pno_start(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params);
+static int android_pno_stop(struct i802_bss *bss);
+#endif /* ANDROID */
+#ifdef ANDROID_P2P
static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
enum wpa_event_type type,
const u8 *frame, size_t len);
-int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
const struct wpabuf *proberesp,
const struct wpabuf *assocresp);
-#endif
+#endif
#ifdef HOSTAPD
static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
@@ -222,12 +332,19 @@ static int wpa_driver_nl80211_if_remove(void *priv,
enum wpa_driver_if_type type,
const char *ifname);
#else /* HOSTAPD */
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
{
return 0;
}
#endif /* HOSTAPD */
-
#ifdef ANDROID
extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
size_t buf_len);
@@ -238,12 +355,36 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
int ifindex, int disabled);
static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
+static int wpa_driver_nl80211_authenticate_retry(
+ struct wpa_driver_nl80211_data *drv);
+
+
+static int is_ap_interface(enum nl80211_iftype nlmode)
+{
+ return (nlmode == NL80211_IFTYPE_AP ||
+ nlmode == NL80211_IFTYPE_P2P_GO);
+}
+
+
+static int is_sta_interface(enum nl80211_iftype nlmode)
+{
+ return (nlmode == NL80211_IFTYPE_STATION ||
+ nlmode == NL80211_IFTYPE_P2P_CLIENT);
+}
+
+
+static int is_p2p_interface(enum nl80211_iftype nlmode)
+{
+ return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
+ nlmode == NL80211_IFTYPE_P2P_GO);
+}
struct nl80211_bss_info_arg {
struct wpa_driver_nl80211_data *drv;
struct wpa_scan_results *res;
unsigned int assoc_freq;
+ u8 assoc_bssid[ETH_ALEN];
};
static int bss_info_handler(struct nl_msg *msg, void *arg);
@@ -279,7 +420,7 @@ static int no_seq_check(struct nl_msg *msg, void *arg)
}
-static int send_and_recv(struct wpa_driver_nl80211_data *drv,
+static int send_and_recv(struct nl80211_global *global,
struct nl_handle *nl_handle, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
void *valid_data)
@@ -287,7 +428,7 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv,
struct nl_cb *cb;
int err = -ENOMEM;
- cb = nl_cb_clone(drv->nl_cb);
+ cb = nl_cb_clone(global->nl_cb);
if (!cb)
goto out;
@@ -314,13 +455,22 @@ static int send_and_recv(struct wpa_driver_nl80211_data *drv,
}
+static int send_and_recv_msgs_global(struct nl80211_global *global,
+ struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data)
+{
+ return send_and_recv(global, global->nl, msg, valid_handler,
+ valid_data);
+}
+
int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
void *valid_data)
{
- return send_and_recv(drv, drv->nl_handle, msg, valid_handler,
- valid_data);
+ return send_and_recv(drv->global, drv->global->nl, msg,
+ valid_handler, valid_data);
}
@@ -361,7 +511,7 @@ static int family_handler(struct nl_msg *msg, void *arg)
}
-static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
+static int nl_get_multicast_id(struct nl80211_global *global,
const char *family, const char *group)
{
struct nl_msg *msg;
@@ -371,11 +521,11 @@ static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
+ genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
0, 0, CTRL_CMD_GETFAMILY, 0);
NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
- ret = send_and_recv_msgs(drv, msg, family_handler, &res);
+ ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
msg = NULL;
if (ret == 0)
ret = res.id;
@@ -386,6 +536,235 @@ nla_put_failure:
}
+static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg, int flags, uint8_t cmd)
+{
+ return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
+ 0, flags, cmd, 0);
+}
+
+
+struct wiphy_idx_data {
+ int wiphy_idx;
+};
+
+
+static int netdev_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wiphy_idx_data *info = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_WIPHY])
+ info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_wiphy_index(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ struct wiphy_idx_data data = {
+ .wiphy_idx = -1,
+ };
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+ if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+ return data.wiphy_idx;
+ msg = NULL;
+nla_put_failure:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
+ struct nl80211_wiphy_data *w)
+{
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
+
+ ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
+ "failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+ ret = 0;
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
+{
+ struct nl80211_wiphy_data *w = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Beacon event message available");
+
+ nl_recvmsgs(handle, w->nl_cb);
+}
+
+
+static int process_beacon_event(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_wiphy_data *w = arg;
+ struct wpa_driver_nl80211_data *drv;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ union wpa_event_data event;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (gnlh->cmd != NL80211_CMD_FRAME) {
+ wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
+ gnlh->cmd);
+ return NL_SKIP;
+ }
+
+ if (!tb[NL80211_ATTR_FRAME])
+ return NL_SKIP;
+
+ dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
+ wiphy_list) {
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
+ event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+ }
+
+ return NL_SKIP;
+}
+
+
+static struct nl80211_wiphy_data *
+nl80211_get_wiphy_data_ap(struct i802_bss *bss)
+{
+ static DEFINE_DL_LIST(nl80211_wiphys);
+ struct nl80211_wiphy_data *w;
+ int wiphy_idx, found = 0;
+ struct i802_bss *tmp_bss;
+
+ if (bss->wiphy_data != NULL)
+ return bss->wiphy_data;
+
+ wiphy_idx = nl80211_get_wiphy_index(bss);
+
+ dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
+ if (w->wiphy_idx == wiphy_idx)
+ goto add;
+ }
+
+ /* alloc new one */
+ w = os_zalloc(sizeof(*w));
+ if (w == NULL)
+ return NULL;
+ w->wiphy_idx = wiphy_idx;
+ dl_list_init(&w->bsss);
+ dl_list_init(&w->drvs);
+
+ w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!w->nl_cb) {
+ os_free(w);
+ return NULL;
+ }
+ nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+ nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
+ w);
+
+ w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
+ "wiphy beacons");
+ if (w->nl_beacons == NULL) {
+ os_free(w);
+ return NULL;
+ }
+
+ if (nl80211_register_beacons(bss->drv, w)) {
+ nl_destroy_handles(&w->nl_beacons);
+ os_free(w);
+ return NULL;
+ }
+
+ eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
+ nl80211_recv_beacons, w, w->nl_beacons);
+
+ dl_list_add(&nl80211_wiphys, &w->list);
+
+add:
+ /* drv entry for this bss already there? */
+ dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+ if (tmp_bss->drv == bss->drv) {
+ found = 1;
+ break;
+ }
+ }
+ /* if not add it */
+ if (!found)
+ dl_list_add(&w->drvs, &bss->drv->wiphy_list);
+
+ dl_list_add(&w->bsss, &bss->wiphy_list);
+ bss->wiphy_data = w;
+ return w;
+}
+
+
+static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
+{
+ struct nl80211_wiphy_data *w = bss->wiphy_data;
+ struct i802_bss *tmp_bss;
+ int found = 0;
+
+ if (w == NULL)
+ return;
+ bss->wiphy_data = NULL;
+ dl_list_del(&bss->wiphy_list);
+
+ /* still any for this drv present? */
+ dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+ if (tmp_bss->drv == bss->drv) {
+ found = 1;
+ break;
+ }
+ }
+ /* if not remove it */
+ if (!found)
+ dl_list_del(&bss->drv->wiphy_list);
+
+ if (!dl_list_empty(&w->bsss))
+ return;
+
+ eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
+
+ nl_cb_put(w->nl_cb);
+ nl_destroy_handles(&w->nl_beacons);
+ dl_list_del(&w->list);
+ os_free(w);
+}
+
+
static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
{
struct i802_bss *bss = priv;
@@ -479,17 +858,33 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
}
+static struct wpa_driver_nl80211_data *
+nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
+{
+ struct wpa_driver_nl80211_data *drv;
+ dl_list_for_each(drv, &global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
+ have_ifidx(drv, idx))
+ return drv;
+ }
+ return NULL;
+}
+
+
static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
struct ifinfomsg *ifi,
u8 *buf, size_t len)
{
- struct wpa_driver_nl80211_data *drv = ctx;
+ struct nl80211_global *global = ctx;
+ struct wpa_driver_nl80211_data *drv;
int attrlen, rta_len;
struct rtattr *attr;
u32 brid = 0;
+ char namebuf[IFNAMSIZ];
- if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) &&
- !have_ifidx(drv, ifi->ifi_index)) {
+ drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+ if (!drv) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
"ifindex %d", ifi->ifi_index);
return;
@@ -504,15 +899,38 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
(ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+ if (if_indextoname(ifi->ifi_index, namebuf) &&
+ linux_iface_up(drv->global->ioctl_sock,
+ drv->first_bss.ifname) > 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+ "event since interface %s is up", namebuf);
+ return;
+ }
wpa_printf(MSG_DEBUG, "nl80211: Interface down");
- drv->if_disabled = 1;
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
+ if (drv->ignore_if_down_event) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+ "event generated by mode change");
+ drv->ignore_if_down_event = 0;
+ } else {
+ drv->if_disabled = 1;
+ wpa_supplicant_event(drv->ctx,
+ EVENT_INTERFACE_DISABLED, NULL);
+ }
}
if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
- wpa_printf(MSG_DEBUG, "nl80211: Interface up");
- drv->if_disabled = 0;
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
+ if (if_indextoname(ifi->ifi_index, namebuf) &&
+ linux_iface_up(drv->global->ioctl_sock,
+ drv->first_bss.ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+ "event since interface %s is down",
+ namebuf);
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface up");
+ drv->if_disabled = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
+ }
}
/*
@@ -524,7 +942,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
if (drv->operstate == 1 &&
(ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
!(ifi->ifi_flags & IFF_RUNNING))
- netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+ netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
-1, IF_OPER_UP);
attrlen = len;
@@ -541,16 +959,13 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
attr = RTA_NEXT(attr, attrlen);
}
-#ifdef HOSTAPD
if (ifi->ifi_family == AF_BRIDGE && brid) {
/* device has been added to bridge */
- char namebuf[IFNAMSIZ];
if_indextoname(brid, namebuf);
wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
brid, namebuf);
add_ifidx(drv, brid);
}
-#endif /* HOSTAPD */
}
@@ -558,11 +973,19 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
struct ifinfomsg *ifi,
u8 *buf, size_t len)
{
- struct wpa_driver_nl80211_data *drv = ctx;
+ struct nl80211_global *global = ctx;
+ struct wpa_driver_nl80211_data *drv;
int attrlen, rta_len;
struct rtattr *attr;
u32 brid = 0;
+ drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+ if (!drv) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for "
+ "foreign ifindex %d", ifi->ifi_index);
+ return;
+ }
+
attrlen = len;
attr = (struct rtattr *) buf;
@@ -578,7 +1001,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
attr = RTA_NEXT(attr, attrlen);
}
-#ifdef HOSTAPD
if (ifi->ifi_family == AF_BRIDGE && brid) {
/* device has been removed from bridge */
char namebuf[IFNAMSIZ];
@@ -587,7 +1009,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
"%s", brid, namebuf);
del_ifidx(drv, brid);
}
-#endif /* HOSTAPD */
}
@@ -629,8 +1050,7 @@ static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
if (!msg)
goto nla_put_failure;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
- NL80211_CMD_GET_SCAN, 0);
+ nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
arg.drv = drv;
@@ -656,12 +1076,12 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
const struct ieee80211_mgmt *mgmt;
union wpa_event_data event;
u16 status;
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
struct wpa_supplicant *wpa_s = drv->ctx;
#endif
mgmt = (const struct ieee80211_mgmt *) frame;
-#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (ANDROID_BRCM_P2P_PATCH)
+#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (ANDROID_P2P)
if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) {
if (len < 24 + sizeof(mgmt->u.assoc_req)) {
wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
@@ -674,7 +1094,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
event.assoc_info.req_ies_len = len - 24 - sizeof(mgmt->u.assoc_req);
event.assoc_info.addr = mgmt->sa;
} else {
-#endif
+#endif
if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
"frame");
@@ -708,7 +1128,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
}
event.assoc_info.freq = drv->assoc_freq;
-#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (ANDROID_BRCM_P2P_PATCH)
+#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (ANDROID_P2P)
}
#endif
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
@@ -765,6 +1185,29 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
}
+static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *reason, struct nlattr *addr)
+{
+ union wpa_event_data data;
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ /*
+ * Avoid reporting two disassociation events that could
+ * confuse the core code.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+ "event when using userspace SME");
+ return;
+ }
+
+ drv->associated = 0;
+ os_memset(&data, 0, sizeof(data));
+ if (reason)
+ data.disassoc_info.reason_code = nla_get_u16(reason);
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
+}
+
+
static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
enum nl80211_commands cmd, struct nlattr *addr)
{
@@ -819,7 +1262,7 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
event.rx_action.data = &mgmt->u.action.category + 1;
event.rx_action.len = frame + len - event.rx_action.data;
wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
} else if (stype == WLAN_FC_STYPE_ASSOC_REQ) {
mlme_event_assoc(drv, frame, len);
} else if (stype == WLAN_FC_STYPE_DISASSOC) {
@@ -835,26 +1278,29 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
}
-static void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv,
- struct nlattr *cookie, const u8 *frame,
- size_t len, struct nlattr *ack)
+static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *cookie, const u8 *frame,
+ size_t len, struct nlattr *ack)
{
union wpa_event_data event;
const struct ieee80211_hdr *hdr;
u16 fc;
- u64 cookie_val;
- if (!cookie)
- return;
+ if (!is_ap_interface(drv->nlmode)) {
+ u64 cookie_val;
- cookie_val = nla_get_u64(cookie);
- wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s "
- "(ack=%d)",
- (long long unsigned int) cookie_val,
- cookie_val == drv->send_action_cookie ?
- " (match)" : " (unknown)", ack != NULL);
- if (cookie_val != drv->send_action_cookie)
- return;
+ if (!cookie)
+ return;
+
+ cookie_val = nla_get_u64(cookie);
+ wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
+ " cookie=0%llx%s (ack=%d)",
+ (long long unsigned int) cookie_val,
+ cookie_val == drv->send_action_cookie ?
+ " (match)" : " (unknown)", ack != NULL);
+ if (cookie_val != drv->send_action_cookie)
+ return;
+ }
hdr = (const struct ieee80211_hdr *) frame;
fc = le_to_host16(hdr->frame_control);
@@ -906,7 +1352,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
reason_code = le_to_host16(mgmt->u.deauth.reason_code);
if (type == EVENT_DISASSOC) {
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
if (drv->nlmode == NL80211_IFTYPE_AP ||
drv->nlmode == NL80211_IFTYPE_P2P_GO) {
event.disassoc_info.addr = mgmt->sa;
@@ -920,7 +1366,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
mgmt->u.disassoc.variable;
}
} else {
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
if (drv->nlmode == NL80211_IFTYPE_AP ||
drv->nlmode == NL80211_IFTYPE_P2P_GO) {
event.deauth_info.addr = mgmt->sa;
@@ -1011,8 +1457,8 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv,
mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame));
break;
case NL80211_CMD_FRAME_TX_STATUS:
- mlme_event_action_tx_status(drv, cookie, nla_data(frame),
- nla_len(frame), ack);
+ mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
+ nla_len(frame), ack);
break;
case NL80211_CMD_UNPROT_DEAUTHENTICATE:
mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
@@ -1117,7 +1563,8 @@ static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
if (cookie != drv->remain_on_chan_cookie)
return; /* not for us */
- drv->pending_remain_on_chan = !cancel_event;
+ if (cancel_event)
+ drv->pending_remain_on_chan = 0;
os_memset(&data, 0, sizeof(data));
data.remain_on_channel.freq = freq;
@@ -1139,6 +1586,14 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
int freqs[MAX_REPORT_FREQS];
int num_freqs = 0;
+ if (drv->scan_for_auth) {
+ drv->scan_for_auth = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
+ "cfg80211 BSS entry");
+ wpa_driver_nl80211_authenticate_retry(drv);
+ return;
+ }
+
os_memset(&event, 0, sizeof(event));
info = &event.scan_info;
info->aborted = aborted;
@@ -1228,14 +1683,14 @@ static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_GET_STATION, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
return send_and_recv_msgs(drv, msg, get_link_signal, sig);
nla_put_failure:
+ nlmsg_free(msg);
return -ENOBUFS;
}
@@ -1296,13 +1751,88 @@ static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- NLM_F_DUMP, NL80211_CMD_GET_SURVEY, 0);
+ nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+
+static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+ static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+ [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+ };
+ struct wpa_scan_results *scan_results = arg;
+ struct wpa_scan_res *scan_res;
+ size_t i;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
+ return NL_SKIP;
+ }
+
+ if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+ tb[NL80211_ATTR_SURVEY_INFO],
+ survey_policy)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
+ "attributes");
+ return NL_SKIP;
+ }
+
+ if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+ return NL_SKIP;
+
+ if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+ return NL_SKIP;
+
+ for (i = 0; i < scan_results->num; ++i) {
+ scan_res = scan_results->res[i];
+ if (!scan_res)
+ continue;
+ if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+ scan_res->freq)
+ continue;
+ if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
+ continue;
+ scan_res->noise = (s8)
+ nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+ scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_noise_for_scan_results(
+ struct wpa_driver_nl80211_data *drv,
+ struct wpa_scan_results *scan_res)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
+ scan_res);
+ nla_put_failure:
+ nlmsg_free(msg);
return -ENOBUFS;
}
@@ -1385,8 +1915,7 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
addr = nla_data(tb[NL80211_ATTR_MAC]);
wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
- if (drv->nlmode == NL80211_IFTYPE_AP &&
- drv->no_monitor_iface_capab) {
+ if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
u8 *ies = NULL;
size_t ies_len = 0;
if (tb[NL80211_ATTR_IE]) {
@@ -1419,8 +1948,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
MAC2STR(addr));
- if (drv->nlmode == NL80211_IFTYPE_AP &&
- drv->no_monitor_iface_capab) {
+ if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
drv_event_disassoc(drv->ctx, addr);
return;
}
@@ -1434,38 +1962,138 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
}
-static int process_event(struct nl_msg *msg, void *arg)
+static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
{
- struct wpa_driver_nl80211_data *drv = arg;
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
+ static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
+ [NL80211_REKEY_DATA_KEK] = {
+ .minlen = NL80211_KEK_LEN,
+ .maxlen = NL80211_KEK_LEN,
+ },
+ [NL80211_REKEY_DATA_KCK] = {
+ .minlen = NL80211_KCK_LEN,
+ .maxlen = NL80211_KCK_LEN,
+ },
+ [NL80211_REKEY_DATA_REPLAY_CTR] = {
+ .minlen = NL80211_REPLAY_CTR_LEN,
+ .maxlen = NL80211_REPLAY_CTR_LEN,
+ },
+ };
union wpa_event_data data;
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_MAC])
+ return;
+ if (!tb[NL80211_ATTR_REKEY_DATA])
+ return;
+ if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
+ tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
+ return;
+ if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
+ MAC2STR(data.driver_gtk_rekey.bssid));
+ data.driver_gtk_rekey.replay_ctr =
+ nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
+ wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
+ data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
+ wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
+}
+
+
+static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
+ static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
+ [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
+ [NL80211_PMKSA_CANDIDATE_BSSID] = {
+ .minlen = ETH_ALEN,
+ .maxlen = ETH_ALEN,
+ },
+ [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
+ };
+ union wpa_event_data data;
+
+ if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
+ return;
+ if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
+ tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
+ return;
+ if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
+ !cand[NL80211_PMKSA_CANDIDATE_BSSID])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.pmkid_candidate.bssid,
+ nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
+ data.pmkid_candidate.index =
+ nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
+ data.pmkid_candidate.preauth =
+ cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+}
- if (tb[NL80211_ATTR_IFINDEX]) {
- int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
- if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
- " for foreign interface (ifindex %d)",
- gnlh->cmd, ifindex);
- return NL_SKIP;
- }
- }
- if (drv->ap_scan_as_station &&
- (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
- gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) {
+static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.client_poll.addr,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
+}
+
+
+static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
+ int wds)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ union wpa_event_data event;
+
+ if (!tb[NL80211_ATTR_MAC])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_from_unknown.bssid = bss->addr;
+ event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
+ event.rx_from_unknown.wds = wds;
+
+ wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
+ int cmd, struct nlattr **tb)
+{
+ if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
+ (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
+ cmd == NL80211_CMD_SCAN_ABORTED)) {
wpa_driver_nl80211_set_mode(&drv->first_bss,
- IEEE80211_MODE_AP);
- drv->ap_scan_as_station = 0;
+ drv->ap_scan_as_station);
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
}
- switch (gnlh->cmd) {
+ switch (cmd) {
case NL80211_CMD_TRIGGER_SCAN:
wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
break;
+ case NL80211_CMD_START_SCHED_SCAN:
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
+ break;
+ case NL80211_CMD_SCHED_SCAN_STOPPED:
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
+ wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
+ break;
case NL80211_CMD_NEW_SCAN_RESULTS:
wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
drv->scan_complete_events = 1;
@@ -1473,6 +2101,11 @@ static int process_event(struct nl_msg *msg, void *arg)
drv->ctx);
send_scan_event(drv, 0, tb);
break;
+ case NL80211_CMD_SCHED_SCAN_RESULTS:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: New sched scan results available");
+ send_scan_event(drv, 0, tb);
+ break;
case NL80211_CMD_SCAN_ABORTED:
wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
/*
@@ -1487,39 +2120,25 @@ static int process_event(struct nl_msg *msg, void *arg)
case NL80211_CMD_ASSOCIATE:
case NL80211_CMD_DEAUTHENTICATE:
case NL80211_CMD_DISASSOCIATE:
- case NL80211_CMD_FRAME:
case NL80211_CMD_FRAME_TX_STATUS:
case NL80211_CMD_UNPROT_DEAUTHENTICATE:
case NL80211_CMD_UNPROT_DISASSOCIATE:
- mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+ mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
tb[NL80211_ATTR_COOKIE]);
break;
case NL80211_CMD_CONNECT:
case NL80211_CMD_ROAM:
- mlme_event_connect(drv, gnlh->cmd,
+ mlme_event_connect(drv, cmd,
tb[NL80211_ATTR_STATUS_CODE],
tb[NL80211_ATTR_MAC],
tb[NL80211_ATTR_REQ_IE],
tb[NL80211_ATTR_RESP_IE]);
break;
case NL80211_CMD_DISCONNECT:
- if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
- /*
- * Avoid reporting two disassociation events that could
- * confuse the core code.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
- "event when using userspace SME");
- break;
- }
- drv->associated = 0;
- os_memset(&data, 0, sizeof(data));
- if (tb[NL80211_ATTR_REASON_CODE])
- data.disassoc_info.reason_code =
- nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
- wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
+ mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
+ tb[NL80211_ATTR_MAC]);
break;
case NL80211_CMD_MICHAEL_MIC_FAILURE:
mlme_event_michael_mic_failure(drv, tb);
@@ -1552,6 +2171,95 @@ static int process_event(struct nl_msg *msg, void *arg)
case NL80211_CMD_DEL_STATION:
nl80211_del_station_event(drv, tb);
break;
+ case NL80211_CMD_SET_REKEY_OFFLOAD:
+ nl80211_rekey_offload_event(drv, tb);
+ break;
+ case NL80211_CMD_PMKSA_CANDIDATE:
+ nl80211_pmksa_candidate_event(drv, tb);
+ break;
+ case NL80211_CMD_PROBE_CLIENT:
+ nl80211_client_probe_event(drv, tb);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
+ "(cmd=%d)", cmd);
+ break;
+ }
+}
+
+
+static int process_drv_event(struct nl_msg *msg, void *arg)
+{
+ struct wpa_driver_nl80211_data *drv = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_IFINDEX]) {
+ int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+ if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
+ " for foreign interface (ifindex %d)",
+ gnlh->cmd, ifindex);
+ return NL_SKIP;
+ }
+ }
+
+ do_process_drv_event(drv, gnlh->cmd, tb);
+ return NL_SKIP;
+}
+
+
+static int process_global_event(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_global *global = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct wpa_driver_nl80211_data *drv;
+ int ifidx = -1;
+
+ 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]);
+
+ dl_list_for_each(drv, &global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ if (ifidx == -1 || ifidx == drv->ifindex ||
+ have_ifidx(drv, ifidx))
+ do_process_drv_event(drv, gnlh->cmd, tb);
+ }
+
+ return NL_SKIP;
+}
+
+
+static int process_bss_event(struct nl_msg *msg, void *arg)
+{
+ struct i802_bss *bss = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ switch (gnlh->cmd) {
+ case NL80211_CMD_FRAME:
+ case NL80211_CMD_FRAME_TX_STATUS:
+ mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+ tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
+ tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+ tb[NL80211_ATTR_COOKIE]);
+ break;
+ case NL80211_CMD_UNEXPECTED_FRAME:
+ nl80211_spurious_frame(bss, tb, 0);
+ break;
+ case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
+ nl80211_spurious_frame(bss, tb, 1);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", gnlh->cmd);
@@ -1565,18 +2273,11 @@ static int process_event(struct nl_msg *msg, void *arg)
static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
void *handle)
{
- struct nl_cb *cb;
- struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ struct nl_cb *cb = eloop_ctx;
wpa_printf(MSG_DEBUG, "nl80211: Event message available");
- cb = nl_cb_clone(drv->nl_cb);
- if (!cb)
- return;
- nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
nl_recvmsgs(handle, cb);
- nl_cb_put(cb);
}
@@ -1604,43 +2305,82 @@ static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
alpha2[1] = alpha2_arg[1];
alpha2[2] = '\0';
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_REQ_SET_REG, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
if (send_and_recv_msgs(drv, msg, NULL, NULL))
return -EINVAL;
return 0;
nla_put_failure:
+ nlmsg_free(msg);
return -EINVAL;
}
struct wiphy_info_data {
- int max_scan_ssids;
- int ap_supported;
- int p2p_supported;
- int auth_supported;
- int connect_supported;
- int offchan_tx_supported;
- int max_remain_on_chan;
+ struct wpa_driver_capa *capa;
+
+ unsigned int error:1;
+ unsigned int device_ap_sme:1;
+ unsigned int poll_command_supported:1;
+ unsigned int data_tx_status:1;
+ unsigned int monitor_supported:1;
};
+static unsigned int probe_resp_offload_support(int supp_protocols)
+{
+ unsigned int prot = 0;
+
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
+
+ return prot;
+}
+
+
static int wiphy_info_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct wiphy_info_data *info = arg;
int p2p_go_supported = 0, p2p_client_supported = 0;
+ int p2p_concurrent = 0;
+ int auth_supported = 0, connect_supported = 0;
+ struct wpa_driver_capa *capa = info->capa;
+ static struct nla_policy
+ iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
+ [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
+ [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
+ [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
+ [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+ },
+ iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
+ [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
+ [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
+ };
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
- info->max_scan_ssids =
+ capa->max_scan_ssids =
nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
+ if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
+ capa->max_sched_scan_ssids =
+ nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+
+ if (tb[NL80211_ATTR_MAX_MATCH_SETS])
+ capa->max_match_sets =
+ nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+
if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
struct nlattr *nl_mode;
int i;
@@ -1648,7 +2388,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
switch (nla_type(nl_mode)) {
case NL80211_IFTYPE_AP:
- info->ap_supported = 1;
+ capa->flags |= WPA_DRIVER_FLAGS_AP;
break;
case NL80211_IFTYPE_P2P_GO:
p2p_go_supported = 1;
@@ -1656,11 +2396,69 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
case NL80211_IFTYPE_P2P_CLIENT:
p2p_client_supported = 1;
break;
+ case NL80211_IFTYPE_MONITOR:
+ info->monitor_supported = 1;
+ break;
}
}
}
- info->p2p_supported = p2p_go_supported && p2p_client_supported;
+ if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
+ struct nlattr *nl_combi;
+ int rem_combi;
+
+ nla_for_each_nested(nl_combi,
+ tb[NL80211_ATTR_INTERFACE_COMBINATIONS],
+ rem_combi) {
+ struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
+ struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
+ struct nlattr *nl_limit, *nl_mode;
+ int err, rem_limit, rem_mode;
+ int combination_has_p2p = 0, combination_has_mgd = 0;
+
+ err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
+ nl_combi,
+ iface_combination_policy);
+ if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
+ !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
+ !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
+ goto broken_combination;
+
+ nla_for_each_nested(nl_limit,
+ tb_comb[NL80211_IFACE_COMB_LIMITS],
+ rem_limit) {
+ err = nla_parse_nested(tb_limit,
+ MAX_NL80211_IFACE_LIMIT,
+ nl_limit,
+ iface_limit_policy);
+ if (err ||
+ !tb_limit[NL80211_IFACE_LIMIT_TYPES])
+ goto broken_combination;
+
+ nla_for_each_nested(
+ nl_mode,
+ tb_limit[NL80211_IFACE_LIMIT_TYPES],
+ rem_mode) {
+ int ift = nla_type(nl_mode);
+ if (ift == NL80211_IFTYPE_P2P_GO ||
+ ift == NL80211_IFTYPE_P2P_CLIENT)
+ combination_has_p2p = 1;
+ if (ift == NL80211_IFTYPE_STATION)
+ combination_has_mgd = 1;
+ }
+ if (combination_has_p2p && combination_has_mgd)
+ break;
+ }
+
+ if (combination_has_p2p && combination_has_mgd) {
+ p2p_concurrent = 1;
+ break;
+ }
+
+broken_combination:
+ ;
+ }
+ }
if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
struct nlattr *nl_cmd;
@@ -1668,21 +2466,92 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
nla_for_each_nested(nl_cmd,
tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
- u32 cmd = nla_get_u32(nl_cmd);
- if (cmd == NL80211_CMD_AUTHENTICATE)
- info->auth_supported = 1;
- else if (cmd == NL80211_CMD_CONNECT)
- info->connect_supported = 1;
+ switch (nla_get_u32(nl_cmd)) {
+ case NL80211_CMD_AUTHENTICATE:
+ auth_supported = 1;
+ break;
+ case NL80211_CMD_CONNECT:
+ connect_supported = 1;
+ break;
+ case NL80211_CMD_START_SCHED_SCAN:
+ capa->sched_scan_supported = 1;
+ break;
+ case NL80211_CMD_PROBE_CLIENT:
+ info->poll_command_supported = 1;
+ break;
+ }
}
}
- if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK])
- info->offchan_tx_supported = 1;
+ if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
+ "off-channel TX");
+ capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
+ }
+
+ if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
+ capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
+ }
+
+ /* default to 5000 since early versions of mac80211 don't set it */
+ capa->max_remain_on_chan = 5000;
+
+ if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
+ capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
- info->max_remain_on_chan =
+ capa->max_remain_on_chan =
nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
+ if (auth_supported)
+ capa->flags |= WPA_DRIVER_FLAGS_SME;
+ else if (!connect_supported) {
+ wpa_printf(MSG_INFO, "nl80211: Driver does not support "
+ "authentication/association or connect commands");
+ info->error = 1;
+ }
+
+ if (p2p_go_supported && p2p_client_supported)
+ capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+ if (p2p_concurrent) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+ "interface (driver advertised support)");
+ capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+ capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+ }
+
+ if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+ if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+ capa->flags |=
+ WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+ }
+ }
+
+ if (tb[NL80211_ATTR_DEVICE_AP_SME])
+ info->device_ap_sme = 1;
+
+ if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
+ u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
+
+ if (flags & NL80211_FEATURE_SK_TX_STATUS)
+ info->data_tx_status = 1;
+ }
+
+ if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
+ int protocols =
+ nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+ wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response "
+ "offload in AP mode");
+ capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
+ capa->probe_resp_offloads =
+ probe_resp_offload_support(protocols);
+ }
+
return NL_SKIP;
}
@@ -1693,16 +2562,13 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg;
os_memset(info, 0, sizeof(*info));
-
- /* default to 5000 since early versions of mac80211 don't set it */
- info->max_remain_on_chan = 5000;
+ info->capa = &drv->capa;
msg = nlmsg_alloc();
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_GET_WIPHY, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
@@ -1720,6 +2586,10 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
struct wiphy_info_data info;
if (wpa_driver_nl80211_get_info(drv, &info))
return -1;
+
+ if (info.error)
+ return -1;
+
drv->has_capability = 1;
/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
@@ -1734,131 +2604,132 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
- drv->capa.max_scan_ssids = info.max_scan_ssids;
- if (info.ap_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
- if (info.auth_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
- else if (!info.connect_supported) {
- wpa_printf(MSG_INFO, "nl80211: Driver does not support "
- "authentication/association or connect commands");
- return -1;
- }
+ drv->device_ap_sme = info.device_ap_sme;
+ drv->poll_command_supported = info.poll_command_supported;
+ drv->data_tx_status = info.data_tx_status;
- if (info.offchan_tx_supported) {
- wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
- "off-channel TX");
- drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
+ /*
+ * If poll command is supported mac80211 is new enough to
+ * have everything we need to not need monitor interfaces.
+ */
+ drv->use_monitor = !info.poll_command_supported;
+
+ if (drv->device_ap_sme && drv->use_monitor) {
+ /*
+ * Non-mac80211 drivers may not support monitor interface.
+ * Make sure we do not get stuck with incorrect capability here
+ * by explicitly testing this.
+ */
+ if (!info.monitor_supported) {
+ wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
+ "with device_ap_sme since no monitor mode "
+ "support detected");
+ drv->use_monitor = 0;
+ }
}
- drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
- drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
- if (info.p2p_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
- drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
- drv->capa.max_remain_on_chan = info.max_remain_on_chan;
+ /*
+ * If we aren't going to use monitor interfaces, but the
+ * driver doesn't support data TX status, we won't get TX
+ * status for EAPOL frames.
+ */
+ if (!drv->use_monitor && !info.data_tx_status)
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
return 0;
}
-static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
+#ifdef ANDROID
+static int android_genl_ctrl_resolve(struct nl_handle *handle,
+ const char *name)
{
- int ret;
-
- /* Initialize generic netlink and nl80211 */
+ /*
+ * Android ICS has very minimal genl_ctrl_resolve() implementation, so
+ * need to work around that.
+ */
+ struct nl_cache *cache = NULL;
+ struct genl_family *nl80211 = NULL;
+ int id = -1;
- drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
- if (drv->nl_cb == NULL) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
- "callbacks");
- goto err1;
+ if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+ "netlink cache");
+ goto fail;
}
- drv->nl_handle = nl80211_handle_alloc(drv->nl_cb);
- if (drv->nl_handle == NULL) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
- "callbacks");
- goto err2;
- }
+ nl80211 = genl_ctrl_search_by_name(cache, name);
+ if (nl80211 == NULL)
+ goto fail;
- drv->nl_handle_event = nl80211_handle_alloc(drv->nl_cb);
- if (drv->nl_handle_event == NULL) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
- "callbacks (event)");
- goto err2b;
- }
+ id = genl_family_get_id(nl80211);
- if (genl_connect(drv->nl_handle)) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
- "netlink");
- goto err3;
- }
+fail:
+ if (nl80211)
+ genl_family_put(nl80211);
+ if (cache)
+ nl_cache_free(cache);
- if (genl_connect(drv->nl_handle_event)) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
- "netlink (event)");
- goto err3;
- }
+ return id;
+}
+#define genl_ctrl_resolve android_genl_ctrl_resolve
+#endif /* ANDROID */
-#ifdef CONFIG_LIBNL20
- if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
- "netlink cache");
- goto err3;
- }
- if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) <
- 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
- "netlink cache (event)");
- goto err3b;
- }
-#else /* CONFIG_LIBNL20 */
- drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
- if (drv->nl_cache == NULL) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
- "netlink cache");
- goto err3;
- }
- drv->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event);
- if (drv->nl_cache_event == NULL) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
- "netlink cache (event)");
- goto err3b;
+
+static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
+{
+ int ret;
+
+ global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (global->nl_cb == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks");
+ return -1;
}
-#endif /* CONFIG_LIBNL20 */
- drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
- if (drv->nl80211 == NULL) {
+ global->nl = nl_create_handle(global->nl_cb, "nl");
+ if (global->nl == NULL)
+ goto err;
+
+ global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
+ if (global->nl80211_id < 0) {
wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
"found");
- goto err4;
+ goto err;
}
- ret = nl_get_multicast_id(drv, "nl80211", "scan");
+ global->nl_event = nl_create_handle(global->nl_cb, "event");
+ if (global->nl_event == NULL)
+ goto err;
+
+ ret = nl_get_multicast_id(global, "nl80211", "scan");
if (ret >= 0)
- ret = nl_socket_add_membership(drv->nl_handle_event, ret);
+ ret = nl_socket_add_membership(global->nl_event, ret);
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
"membership for scan events: %d (%s)",
ret, strerror(-ret));
- goto err4;
+ goto err;
}
- ret = nl_get_multicast_id(drv, "nl80211", "mlme");
+ ret = nl_get_multicast_id(global, "nl80211", "mlme");
if (ret >= 0)
- ret = nl_socket_add_membership(drv->nl_handle_event, ret);
+ ret = nl_socket_add_membership(global->nl_event, ret);
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
"membership for mlme events: %d (%s)",
ret, strerror(-ret));
- goto err4;
+ goto err;
}
- ret = nl_get_multicast_id(drv, "nl80211", "regulatory");
+ ret = nl_get_multicast_id(global, "nl80211", "regulatory");
if (ret >= 0)
- ret = nl_socket_add_membership(drv->nl_handle_event, ret);
+ ret = nl_socket_add_membership(global->nl_event, ret);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
"membership for regulatory events: %d (%s)",
@@ -1866,27 +2737,43 @@ static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
/* Continue without regulatory events */
}
- eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
- wpa_driver_nl80211_event_receive, drv,
- drv->nl_handle_event);
+ nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ no_seq_check, NULL);
+ nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+ process_global_event, global);
+
+ eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
+ wpa_driver_nl80211_event_receive,
+ global->nl_cb, global->nl_event);
return 0;
-err4:
- nl_cache_free(drv->nl_cache_event);
-err3b:
- nl_cache_free(drv->nl_cache);
-err3:
- nl80211_handle_destroy(drv->nl_handle_event);
-err2b:
- nl80211_handle_destroy(drv->nl_handle);
-err2:
- nl_cb_put(drv->nl_cb);
-err1:
+err:
+ nl_destroy_handles(&global->nl_event);
+ nl_destroy_handles(&global->nl);
+ nl_cb_put(global->nl_cb);
+ global->nl_cb = NULL;
return -1;
}
+static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
+{
+ drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!drv->nl_cb) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
+ return -1;
+ }
+
+ nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ no_seq_check, NULL);
+ nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+ process_drv_event, drv);
+
+ return 0;
+}
+
+
static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
{
wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
@@ -1901,7 +2788,8 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
{
struct wpa_driver_nl80211_data *drv = ctx;
wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
- if (linux_set_iface_flags(drv->ioctl_sock, drv->first_bss.ifname, 1)) {
+ if (linux_set_iface_flags(drv->global->ioctl_sock,
+ drv->first_bss.ifname, 1)) {
wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
"after rfkill unblock");
return;
@@ -1943,6 +2831,90 @@ static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
}
+static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
+ void *eloop_ctx,
+ void *handle)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ u8 data[2048];
+ struct msghdr msg;
+ struct iovec entry;
+ struct {
+ struct cmsghdr cm;
+ char control[512];
+ } control;
+ struct cmsghdr *cmsg;
+ int res, found_ee = 0, found_wifi = 0, acked = 0;
+ union wpa_event_data event;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = &entry;
+ msg.msg_iovlen = 1;
+ entry.iov_base = data;
+ entry.iov_len = sizeof(data);
+ msg.msg_control = &control;
+ msg.msg_controllen = sizeof(control);
+
+ res = recvmsg(sock, &msg, MSG_ERRQUEUE);
+ /* if error or not fitting 802.3 header, return */
+ if (res < 14)
+ return;
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_WIFI_STATUS) {
+ int *ack;
+
+ found_wifi = 1;
+ ack = (void *)CMSG_DATA(cmsg);
+ acked = *ack;
+ }
+
+ if (cmsg->cmsg_level == SOL_PACKET &&
+ cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
+ struct sock_extended_err *err =
+ (struct sock_extended_err *)CMSG_DATA(cmsg);
+
+ if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
+ found_ee = 1;
+ }
+ }
+
+ if (!found_ee || !found_wifi)
+ return;
+
+ memset(&event, 0, sizeof(event));
+ event.eapol_tx_status.dst = data;
+ event.eapol_tx_status.data = data + 14;
+ event.eapol_tx_status.data_len = res - 14;
+ event.eapol_tx_status.ack = acked;
+ wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
+}
+
+
+static int nl80211_init_bss(struct i802_bss *bss)
+{
+ bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!bss->nl_cb)
+ return -1;
+
+ nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ no_seq_check, NULL);
+ nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+ process_bss_event, bss);
+
+ return 0;
+}
+
+
+static void nl80211_destroy_bss(struct i802_bss *bss)
+{
+ nl_cb_put(bss->nl_cb);
+ bss->nl_cb = NULL;
+}
+
+
/**
* wpa_driver_nl80211_init - Initialize nl80211 driver interface
* @ctx: context to be used when calling wpa_supplicant functions,
@@ -1955,10 +2927,11 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
void *global_priv)
{
struct wpa_driver_nl80211_data *drv;
- struct netlink_config *cfg;
struct rfkill_config *rcfg;
struct i802_bss *bss;
+ if (global_priv == NULL)
+ return NULL;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
@@ -1969,32 +2942,18 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
drv->monitor_ifidx = -1;
drv->monitor_sock = -1;
- drv->ioctl_sock = -1;
+ drv->eapol_tx_sock = -1;
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
if (wpa_driver_nl80211_init_nl(drv)) {
os_free(drv);
return NULL;
}
- nl80211_get_phy_name(drv);
-
- drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (drv->ioctl_sock < 0) {
- perror("socket(PF_INET,SOCK_DGRAM)");
+ if (nl80211_init_bss(bss))
goto failed;
- }
- cfg = os_zalloc(sizeof(*cfg));
- if (cfg == NULL)
- goto failed;
- cfg->ctx = drv;
- cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
- cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
- drv->netlink = netlink_init(cfg);
- if (drv->netlink == NULL) {
- os_free(cfg);
- goto failed;
- }
+ nl80211_get_phy_name(drv);
rcfg = os_zalloc(sizeof(*rcfg));
if (rcfg == NULL)
@@ -2012,32 +2971,46 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
if (wpa_driver_nl80211_finish_drv_init(drv))
goto failed;
- if (drv->global)
+ drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+ if (drv->eapol_tx_sock < 0)
+ goto failed;
+
+ if (drv->data_tx_status) {
+ int enabled = 1;
+
+ if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
+ &enabled, sizeof(enabled)) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: wifi status sockopt failed\n");
+ drv->data_tx_status = 0;
+ if (!drv->use_monitor)
+ drv->capa.flags &=
+ ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+ } else {
+ eloop_register_read_sock(drv->eapol_tx_sock,
+ wpa_driver_nl80211_handle_eapol_tx_status,
+ drv, NULL);
+ }
+ }
+
+ if (drv->global) {
dl_list_add(&drv->global->interfaces, &drv->list);
+ drv->in_interface_list = 1;
+ }
return bss;
failed:
- rfkill_deinit(drv->rfkill);
- netlink_deinit(drv->netlink);
- if (drv->ioctl_sock >= 0)
- close(drv->ioctl_sock);
-
- genl_family_put(drv->nl80211);
- nl_cache_free(drv->nl_cache);
- nl80211_handle_destroy(drv->nl_handle);
- nl_cb_put(drv->nl_cb);
- eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-
- os_free(drv);
+ wpa_driver_nl80211_deinit(bss);
return NULL;
}
-static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv,
+static int nl80211_register_frame(struct i802_bss *bss,
struct nl_handle *nl_handle,
u16 type, const u8 *match, size_t match_len)
{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret = -1;
@@ -2045,14 +3018,18 @@ static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv,
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_REGISTER_ACTION, 0);
+ wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p",
+ type, nl_handle);
+ wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
+ match, match_len);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
- ret = send_and_recv(drv, nl_handle, msg, NULL, NULL);
+ ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
@@ -2069,58 +3046,213 @@ nla_put_failure:
}
-static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv,
+static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (bss->nl_mgmt) {
+ wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
+ "already on! (nl_mgmt=%p)", bss->nl_mgmt);
+ return -1;
+ }
+
+ bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
+ if (bss->nl_mgmt == NULL)
+ return -1;
+
+ eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
+ wpa_driver_nl80211_event_receive, bss->nl_cb,
+ bss->nl_mgmt);
+
+ return 0;
+}
+
+
+static int nl80211_register_action_frame(struct i802_bss *bss,
const u8 *match, size_t match_len)
{
u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
- return nl80211_register_frame(drv, drv->nl_handle_event,
+ return nl80211_register_frame(bss, bss->nl_mgmt,
type, match, match_len);
}
-static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
+static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
{
-#ifdef CONFIG_P2P
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (nl80211_alloc_mgmt_handle(bss))
+ return -1;
+ wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
+ "handle %p", bss->nl_mgmt);
+
+#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
/* GAS Initial Request */
- if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0a", 2) < 0)
+ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
return -1;
/* GAS Initial Response */
- if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0b", 2) < 0)
+ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
return -1;
/* GAS Comeback Request */
- if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0c", 2) < 0)
+ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
return -1;
/* GAS Comeback Response */
- if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0d", 2) < 0)
+ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
return -1;
+#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
+#ifdef CONFIG_P2P
/* P2P Public Action */
- if (nl80211_register_action_frame(drv,
+ if (nl80211_register_action_frame(bss,
(u8 *) "\x04\x09\x50\x6f\x9a\x09",
6) < 0)
return -1;
/* P2P Action */
- if (nl80211_register_action_frame(drv,
+ if (nl80211_register_action_frame(bss,
(u8 *) "\x7f\x50\x6f\x9a\x09",
5) < 0)
return -1;
#endif /* CONFIG_P2P */
#ifdef CONFIG_IEEE80211W
/* SA Query Response */
- if (nl80211_register_action_frame(drv, (u8 *) "\x08\x01", 2) < 0)
+ if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
return -1;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_TDLS
+ if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
+ /* TDLS Discovery Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
+ 0)
+ return -1;
+ }
+#endif /* CONFIG_TDLS */
/* FT Action frames */
- if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0)
+ if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
return -1;
else
drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+ /* WNM - BSS Transition Management Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
+ return -1;
+
return 0;
}
+static int nl80211_register_spurious_class3(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+ ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
+ "failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+ ret = 0;
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
+{
+ static const int stypes[] = {
+ WLAN_FC_STYPE_AUTH,
+ WLAN_FC_STYPE_ASSOC_REQ,
+ WLAN_FC_STYPE_REASSOC_REQ,
+ WLAN_FC_STYPE_DISASSOC,
+ WLAN_FC_STYPE_DEAUTH,
+ WLAN_FC_STYPE_ACTION,
+ WLAN_FC_STYPE_PROBE_REQ,
+/* Beacon doesn't work as mac80211 doesn't currently allow
+ * it, but it wouldn't really be the right thing anyway as
+ * it isn't per interface ... maybe just dump the scan
+ * results periodically for OLBC?
+ */
+// WLAN_FC_STYPE_BEACON,
+ };
+ unsigned int i;
+
+ if (nl80211_alloc_mgmt_handle(bss))
+ return -1;
+ wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
+ "handle %p", bss->nl_mgmt);
+
+ for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
+ if (nl80211_register_frame(bss, bss->nl_mgmt,
+ (WLAN_FC_TYPE_MGMT << 2) |
+ (stypes[i] << 4),
+ NULL, 0) < 0) {
+ goto out_err;
+ }
+ }
+
+ if (nl80211_register_spurious_class3(bss))
+ goto out_err;
+
+ if (nl80211_get_wiphy_data_ap(bss) == NULL)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+ nl_destroy_handles(&bss->nl_mgmt);
+ return -1;
+}
+
+
+static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
+{
+ if (nl80211_alloc_mgmt_handle(bss))
+ return -1;
+ wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
+ "handle %p (device SME)", bss->nl_mgmt);
+
+ if (nl80211_register_frame(bss, bss->nl_mgmt,
+ (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_ACTION << 4),
+ NULL, 0) < 0)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+ nl_destroy_handles(&bss->nl_mgmt);
+ return -1;
+}
+
+
+static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
+{
+ if (bss->nl_mgmt == NULL)
+ return;
+ wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
+ "(%s)", bss->nl_mgmt, reason);
+ eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+ nl_destroy_handles(&bss->nl_mgmt);
+
+ nl80211_put_wiphy_data_ap(bss);
+}
+
+
static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
{
wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
@@ -2137,12 +3269,19 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
drv->first_bss.ifindex = drv->ifindex;
#ifndef HOSTAPD
- if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) {
- wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
+ /*
+ * 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");
+ return -1;
}
- if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
if (rfkill_is_blocked(drv->rfkill)) {
wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
"interface '%s' due to rfkill",
@@ -2156,26 +3295,17 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
}
}
- netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+ netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
1, IF_OPER_DORMANT);
#endif /* HOSTAPD */
if (wpa_driver_nl80211_capa(drv))
return -1;
- if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, drv->addr))
+ if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+ bss->addr))
return -1;
- if (nl80211_register_action_frames(drv) < 0) {
- wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
- "frame processing - ignore for now");
- /*
- * Older kernel versions did not support this, so ignore the
- * error for now. Some functionality may not be available
- * because of this.
- */
- }
-
if (send_rfkill_event) {
eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
drv, drv->ctx);
@@ -2193,12 +3323,12 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_DEL_BEACON, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
return send_and_recv_msgs(drv, msg, NULL, NULL);
nla_put_failure:
+ nlmsg_free(msg);
return -ENOBUFS;
}
@@ -2215,17 +3345,22 @@ static void wpa_driver_nl80211_deinit(void *priv)
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- if (drv->nl_handle_preq)
+ if (drv->data_tx_status)
+ eloop_unregister_read_sock(drv->eapol_tx_sock);
+ if (drv->eapol_tx_sock >= 0)
+ close(drv->eapol_tx_sock);
+
+ if (bss->nl_preq)
wpa_driver_nl80211_probe_req_report(bss, 0);
if (bss->added_if_into_bridge) {
- if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
- < 0)
+ if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+ bss->ifname) < 0)
wpa_printf(MSG_INFO, "nl80211: Failed to remove "
"interface %s from bridge %s: %s",
bss->ifname, bss->brname, strerror(errno));
}
if (bss->added_bridge) {
- if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
+ if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
wpa_printf(MSG_INFO, "nl80211: Failed to remove "
"bridge %s: %s",
bss->brname, strerror(errno));
@@ -2233,7 +3368,7 @@ static void wpa_driver_nl80211_deinit(void *priv)
nl80211_remove_monitor_interface(drv);
- if (drv->nlmode == NL80211_IFTYPE_AP)
+ if (is_ap_interface(drv->nlmode))
wpa_driver_nl80211_del_beacon(drv);
#ifdef HOSTAPD
@@ -2254,32 +3389,28 @@ static void wpa_driver_nl80211_deinit(void *priv)
os_free(drv->if_indices);
#endif /* HOSTAPD */
- if (drv->disable_11b_rates)
+ if (drv->disabled_11b_rates)
nl80211_disable_11b_rates(drv, drv->ifindex, 0);
- netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
- netlink_deinit(drv->netlink);
+ netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
+ IF_OPER_UP);
rfkill_deinit(drv->rfkill);
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
- (void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
- wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA);
-
- if (drv->ioctl_sock >= 0)
- close(drv->ioctl_sock);
+ (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");
- eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
- genl_family_put(drv->nl80211);
- nl_cache_free(drv->nl_cache);
- nl_cache_free(drv->nl_cache_event);
- nl80211_handle_destroy(drv->nl_handle);
- nl80211_handle_destroy(drv->nl_handle_event);
nl_cb_put(drv->nl_cb);
+ nl80211_destroy_bss(&drv->first_bss);
+
os_free(drv->filter_ssids);
- if (drv->global)
+ os_free(drv->auth_ie);
+
+ if (drv->in_interface_list)
dl_list_del(&drv->list);
os_free(drv);
@@ -2297,10 +3428,10 @@ static void wpa_driver_nl80211_deinit(void *priv)
static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_driver_nl80211_data *drv = eloop_ctx;
- if (drv->ap_scan_as_station) {
+ if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
wpa_driver_nl80211_set_mode(&drv->first_bss,
- IEEE80211_MODE_AP);
- drv->ap_scan_as_station = 0;
+ drv->ap_scan_as_station);
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
}
wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
@@ -2319,16 +3450,20 @@ static int wpa_driver_nl80211_scan(void *priv,
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = 0, timeout;
- struct nl_msg *msg, *ssids, *freqs;
+ struct nl_msg *msg, *ssids, *freqs, *rates;
size_t i;
+ drv->scan_for_auth = 0;
+
msg = nlmsg_alloc();
ssids = nlmsg_alloc();
freqs = nlmsg_alloc();
- if (!msg || !ssids || !freqs) {
+ rates = nlmsg_alloc();
+ if (!msg || !ssids || !freqs || !rates) {
nlmsg_free(msg);
nlmsg_free(ssids);
nlmsg_free(freqs);
+ nlmsg_free(rates);
return -1;
}
@@ -2337,8 +3472,7 @@ static int wpa_driver_nl80211_scan(void *priv,
params->filter_ssids = NULL;
drv->num_filter_ssids = params->num_filter_ssids;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_TRIGGER_SCAN, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
@@ -2353,8 +3487,8 @@ static int wpa_driver_nl80211_scan(void *priv,
nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
if (params->extra_ies) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs",
- params->extra_ies, params->extra_ies_len);
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+ params->extra_ies, params->extra_ies_len);
NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
params->extra_ies);
}
@@ -2368,29 +3502,42 @@ static int wpa_driver_nl80211_scan(void *priv,
nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
}
+ if (params->p2p_probe) {
+ /*
+ * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
+ * by masking out everything else apart from the OFDM rates 6,
+ * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
+ * rates are left enabled.
+ */
+ NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
+ "\x0c\x12\x18\x24\x30\x48\x60\x6c");
+ nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates);
+
+ NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
"(%s)", ret, strerror(-ret));
#ifdef HOSTAPD
- if (drv->nlmode == NL80211_IFTYPE_AP) {
+ if (is_ap_interface(drv->nlmode)) {
/*
* mac80211 does not allow scan requests in AP mode, so
* try to do this in station mode.
*/
- if (wpa_driver_nl80211_set_mode(bss,
- IEEE80211_MODE_INFRA))
+ if (wpa_driver_nl80211_set_mode(
+ bss, NL80211_IFTYPE_STATION))
goto nla_put_failure;
if (wpa_driver_nl80211_scan(drv, params)) {
- wpa_driver_nl80211_set_mode(bss,
- IEEE80211_MODE_AP);
+ wpa_driver_nl80211_set_mode(bss, drv->nlmode);
goto nla_put_failure;
}
/* Restore AP mode when processing scan results */
- drv->ap_scan_as_station = 1;
+ drv->ap_scan_as_station = drv->nlmode;
ret = 0;
} else
goto nla_put_failure;
@@ -2420,6 +3567,165 @@ nla_put_failure:
nlmsg_free(ssids);
nlmsg_free(msg);
nlmsg_free(freqs);
+ nlmsg_free(rates);
+ return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * @interval: Interval between scan cycles in milliseconds
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+static int wpa_driver_nl80211_sched_scan(void *priv,
+ struct wpa_driver_scan_params *params,
+ u32 interval)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = 0;
+ struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
+ size_t i;
+
+#ifdef ANDROID
+ if (!drv->capa.sched_scan_supported)
+ return android_pno_start(bss, params);
+#endif /* ANDROID */
+
+ msg = nlmsg_alloc();
+ ssids = nlmsg_alloc();
+ freqs = nlmsg_alloc();
+ if (!msg || !ssids || !freqs) {
+ nlmsg_free(msg);
+ nlmsg_free(ssids);
+ nlmsg_free(freqs);
+ return -1;
+ }
+
+ os_free(drv->filter_ssids);
+ drv->filter_ssids = params->filter_ssids;
+ params->filter_ssids = NULL;
+ drv->num_filter_ssids = params->num_filter_ssids;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
+
+ if (drv->num_filter_ssids &&
+ (int) drv->num_filter_ssids <= drv->capa.max_match_sets) {
+ match_sets = nlmsg_alloc();
+
+ for (i = 0; i < drv->num_filter_ssids; i++) {
+ wpa_hexdump_ascii(MSG_MSGDUMP,
+ "nl80211: Sched scan filter SSID",
+ drv->filter_ssids[i].ssid,
+ drv->filter_ssids[i].ssid_len);
+
+ match_set_ssid = nlmsg_alloc();
+ nla_put(match_set_ssid,
+ NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+ drv->filter_ssids[i].ssid_len,
+ drv->filter_ssids[i].ssid);
+
+ nla_put_nested(match_sets, i + 1, match_set_ssid);
+
+ nlmsg_free(match_set_ssid);
+ }
+
+ nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
+ match_sets);
+ nlmsg_free(match_sets);
+ }
+
+ for (i = 0; i < params->num_ssids; i++) {
+ wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan SSID",
+ params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
+ params->ssids[i].ssid);
+ }
+ if (params->num_ssids)
+ nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+
+ if (params->extra_ies) {
+ wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan extra IEs",
+ params->extra_ies, params->extra_ies_len);
+ NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
+ params->extra_ies);
+ }
+
+ if (params->freqs) {
+ for (i = 0; params->freqs[i]; i++) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
+ "MHz", params->freqs[i]);
+ NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+ }
+ nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
+ /* TODO: if we get an error here, we should fall back to normal scan */
+
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
+ "ret=%d (%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
+ "scan interval %d msec", ret, interval);
+
+nla_put_failure:
+ nlmsg_free(ssids);
+ nlmsg_free(msg);
+ nlmsg_free(freqs);
+ return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+static int wpa_driver_nl80211_stop_sched_scan(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = 0;
+ struct nl_msg *msg;
+
+#ifdef ANDROID
+ if (!drv->capa.sched_scan_supported)
+ return android_pno_stop(bss);
+#endif /* ANDROID */
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: "
+ "ret=%d (%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret);
+
+nla_put_failure:
+ nlmsg_free(msg);
return ret;
}
@@ -2514,6 +3820,13 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
_arg->assoc_freq);
}
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_BSSID]) {
+ os_memcpy(_arg->assoc_bssid,
+ nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+ MACSTR, MAC2STR(_arg->assoc_bssid));
+ }
}
if (!res)
return NL_SKIP;
@@ -2555,7 +3868,7 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
} else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
- r->flags |= WPA_SCAN_LEVEL_INVALID;
+ r->flags |= WPA_SCAN_QUAL_INVALID;
} else
r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
if (bss[NL80211_BSS_TSF])
@@ -2657,7 +3970,7 @@ static void wpa_driver_nl80211_check_bss_status(
"indicates BSS status with " MACSTR
" as authenticated",
MAC2STR(r->bssid));
- if (drv->nlmode == NL80211_IFTYPE_STATION &&
+ if (is_sta_interface(drv->nlmode) &&
os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
0) {
@@ -2675,13 +3988,13 @@ static void wpa_driver_nl80211_check_bss_status(
"indicate BSS status with " MACSTR
" as associated",
MAC2STR(r->bssid));
- if (drv->nlmode == NL80211_IFTYPE_STATION &&
+ if (is_sta_interface(drv->nlmode) &&
!drv->associated) {
wpa_printf(MSG_DEBUG, "nl80211: Local state "
"(not associated) does not match "
"with BSS state");
clear_state_mismatch(drv, r->bssid);
- } else if (drv->nlmode == NL80211_IFTYPE_STATION &&
+ } else if (is_sta_interface(drv->nlmode) &&
os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
0) {
wpa_printf(MSG_DEBUG, "nl80211: Local state "
@@ -2696,20 +4009,6 @@ static void wpa_driver_nl80211_check_bss_status(
}
-static void wpa_scan_results_free(struct wpa_scan_results *res)
-{
- size_t i;
-
- if (res == NULL)
- return;
-
- for (i = 0; i < res->num; i++)
- os_free(res->res[i]);
- os_free(res->res);
- os_free(res);
-}
-
-
static struct wpa_scan_results *
nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
{
@@ -2725,8 +4024,7 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
if (!msg)
goto nla_put_failure;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
- NL80211_CMD_GET_SCAN, 0);
+ nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
arg.drv = drv;
@@ -2734,8 +4032,9 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
msg = NULL;
if (ret == 0) {
- wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
- (unsigned long) res->num);
+ wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
+ "BSSes)", (unsigned long) res->num);
+ nl80211_get_noise_for_scan_results(drv, res);
return res;
}
wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
@@ -2806,17 +4105,19 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
"set_tx=%d seq_len=%lu key_len=%lu",
__func__, ifindex, alg, addr, key_idx, set_tx,
(unsigned long) seq_len, (unsigned long) key_len);
+#ifdef CONFIG_TDLS
+ if (key_idx == -1)
+ key_idx = 0;
+#endif /* CONFIG_TDLS */
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
if (alg == WPA_ALG_NONE) {
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_DEL_KEY, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
} else {
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_NEW_KEY, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
switch (alg) {
case WPA_ALG_WEP:
@@ -2889,7 +4190,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
*/
if (ret || !set_tx || alg == WPA_ALG_NONE)
return ret;
- if (drv->nlmode == NL80211_IFTYPE_AP && addr &&
+ if (is_ap_interface(drv->nlmode) && addr &&
!is_broadcast_ether_addr(addr))
return ret;
@@ -2897,8 +4198,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_KEY, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY);
NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
if (alg == WPA_ALG_IGTK)
@@ -2940,6 +4240,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
return ret;
nla_put_failure:
+ nlmsg_free(msg);
return -ENOBUFS;
}
@@ -3069,7 +4370,7 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0);
+ nl80211_cmd(drv, msg, 0, cmd);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
@@ -3080,8 +4381,9 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
- "(%s)", ret, strerror(-ret));
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: MLME command failed: reason=%u ret=%d (%s)",
+ reason_code, ret, strerror(-ret));
goto nla_put_failure;
}
ret = 0;
@@ -3134,6 +4436,52 @@ static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
}
+static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_auth_params *params)
+{
+ int i;
+
+ drv->auth_freq = params->freq;
+ drv->auth_alg = params->auth_alg;
+ drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
+ drv->auth_local_state_change = params->local_state_change;
+ drv->auth_p2p = params->p2p;
+
+ if (params->bssid)
+ os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
+ else
+ os_memset(drv->auth_bssid_, 0, ETH_ALEN);
+
+ if (params->ssid) {
+ os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
+ drv->auth_ssid_len = params->ssid_len;
+ } else
+ drv->auth_ssid_len = 0;
+
+
+ os_free(drv->auth_ie);
+ drv->auth_ie = NULL;
+ drv->auth_ie_len = 0;
+ if (params->ie) {
+ drv->auth_ie = os_malloc(params->ie_len);
+ if (drv->auth_ie) {
+ os_memcpy(drv->auth_ie, params->ie, params->ie_len);
+ drv->auth_ie_len = params->ie_len;
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (params->wep_key[i] && params->wep_key_len[i] &&
+ params->wep_key_len[i] <= 16) {
+ os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
+ params->wep_key_len[i]);
+ drv->auth_wep_key_len[i] = params->wep_key_len[i];
+ } else
+ drv->auth_wep_key_len[i] = 0;
+ }
+}
+
+
static int wpa_driver_nl80211_authenticate(
void *priv, struct wpa_driver_auth_params *params)
{
@@ -3142,13 +4490,20 @@ static int wpa_driver_nl80211_authenticate(
int ret = -1, i;
struct nl_msg *msg;
enum nl80211_auth_type type;
+ enum nl80211_iftype nlmode;
int count = 0;
+ int is_retry;
+
+ is_retry = drv->retry_auth;
+ drv->retry_auth = 0;
drv->associated = 0;
os_memset(drv->auth_bssid, 0, ETH_ALEN);
/* FIX: IBSS mode */
- if (drv->nlmode != NL80211_IFTYPE_STATION &&
- wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0)
+ nlmode = params->p2p ?
+ NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+ if (drv->nlmode != nlmode &&
+ wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
retry:
@@ -3159,8 +4514,7 @@ retry:
wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
drv->ifindex);
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_AUTHENTICATE, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
for (i = 0; i < 4; i++) {
if (!params->wep_key[i])
@@ -3218,8 +4572,9 @@ retry:
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
- "(%s)", ret, strerror(-ret));
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: MLME command failed (auth): ret=%d (%s)",
+ ret, strerror(-ret));
count++;
if (ret == -EALREADY && count == 1 && params->bssid &&
!params->local_state_change) {
@@ -3236,6 +4591,49 @@ retry:
nlmsg_free(msg);
goto retry;
}
+
+ if (ret == -ENOENT && params->freq && !is_retry) {
+ /*
+ * cfg80211 has likely expired the BSS entry even
+ * though it was previously available in our internal
+ * BSS table. To recover quickly, start a single
+ * channel scan on the specified channel.
+ */
+ struct wpa_driver_scan_params scan;
+ int freqs[2];
+
+ os_memset(&scan, 0, sizeof(scan));
+ scan.num_ssids = 1;
+ if (params->ssid) {
+ scan.ssids[0].ssid = params->ssid;
+ scan.ssids[0].ssid_len = params->ssid_len;
+ }
+ freqs[0] = params->freq;
+ freqs[1] = 0;
+ scan.freqs = freqs;
+ wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
+ "channel scan to refresh cfg80211 BSS "
+ "entry");
+ ret = wpa_driver_nl80211_scan(bss, &scan);
+ if (ret == 0) {
+ nl80211_copy_auth_params(drv, params);
+ drv->scan_for_auth = 1;
+ }
+ } else if (is_retry) {
+ /*
+ * Need to indicate this with an event since the return
+ * value from the retry is not delivered to core code.
+ */
+ union wpa_event_data event;
+ wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
+ "failed");
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
+ ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
+ &event);
+ }
+
goto nla_put_failure;
}
ret = 0;
@@ -3248,6 +4646,45 @@ nla_put_failure:
}
+static int wpa_driver_nl80211_authenticate_retry(
+ struct wpa_driver_nl80211_data *drv)
+{
+ struct wpa_driver_auth_params params;
+ struct i802_bss *bss = &drv->first_bss;
+ int i;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
+
+ os_memset(&params, 0, sizeof(params));
+ params.freq = drv->auth_freq;
+ params.auth_alg = drv->auth_alg;
+ params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
+ params.local_state_change = drv->auth_local_state_change;
+ params.p2p = drv->auth_p2p;
+
+ if (!is_zero_ether_addr(drv->auth_bssid_))
+ params.bssid = drv->auth_bssid_;
+
+ if (drv->auth_ssid_len) {
+ params.ssid = drv->auth_ssid;
+ params.ssid_len = drv->auth_ssid_len;
+ }
+
+ params.ie = drv->auth_ie;
+ params.ie_len = drv->auth_ie_len;
+
+ for (i = 0; i < 4; i++) {
+ if (drv->auth_wep_key_len[i]) {
+ params.wep_key[i] = drv->auth_wep_key[i];
+ params.wep_key_len[i] = drv->auth_wep_key_len[i];
+ }
+ }
+
+ drv->retry_auth = 1;
+ return wpa_driver_nl80211_authenticate(bss, &params);
+}
+
+
struct phy_info_arg {
u16 *num_modes;
struct hostapd_hw_modes *modes;
@@ -3300,6 +4737,7 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
mode = &phy_info->modes[*(phy_info->num_modes)];
memset(mode, 0, sizeof(*mode));
+ mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
*(phy_info->num_modes) += 1;
nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
@@ -3640,8 +5078,7 @@ static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_GET_REG, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
}
@@ -3664,8 +5101,7 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
if (!msg)
return NULL;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_GET_WIPHY, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
@@ -3673,14 +5109,16 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
nl80211_set_ht40_flags(drv, &result);
return wpa_driver_nl80211_add_11b(result.modes, num_modes);
}
+ msg = NULL;
nla_put_failure:
+ nlmsg_free(msg);
return NULL;
}
-static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
- const void *data, size_t len,
- int encrypt)
+static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
+ const void *data, size_t len,
+ int encrypt, int noack)
{
__u8 rtap_hdr[] = {
0x00, 0x00, /* radiotap version */
@@ -3711,6 +5149,7 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
.msg_flags = 0,
};
int res;
+ u16 txflags = 0;
if (encrypt)
rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
@@ -3721,6 +5160,10 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
return -1;
}
+ if (noack)
+ txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
+ *(le16 *) &rtap_hdr[12] = host_to_le16(txflags);
+
res = sendmsg(drv->monitor_sock, &msg, 0);
if (res < 0) {
wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
@@ -3730,8 +5173,24 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
}
+static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
+ const void *data, size_t len,
+ int encrypt, int noack)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ u64 cookie;
+
+ if (drv->use_monitor)
+ return wpa_driver_nl80211_send_mntr(drv, data, len,
+ encrypt, noack);
+
+ return nl80211_send_frame_cmd(bss, bss->freq, 0, data, len,
+ &cookie, 0, noack, 0);
+}
+
+
static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
- size_t data_len)
+ size_t data_len, int noack)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -3741,7 +5200,8 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
mgmt = (struct ieee80211_mgmt *) data;
fc = le_to_host16(mgmt->frame_control);
- if (drv->nlmode == NL80211_IFTYPE_STATION &&
+
+ if (is_sta_interface(drv->nlmode) &&
WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
/*
@@ -3749,19 +5209,21 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
* but it works due to the single-threaded nature
* of wpa_supplicant.
*/
- return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq, 0,
- data, data_len, NULL);
+ return nl80211_send_frame_cmd(bss, drv->last_mgmt_freq, 0,
+ data, data_len, NULL, 1, noack,
+ 1);
}
-#ifdef ANDROID_BRCM_P2P_PATCH
- if (drv->nlmode == NL80211_IFTYPE_AP) {
- wpa_printf(MSG_DEBUG, "%s: Sending frame on ap_oper_freq %d using nl80211_send_frame_cmd", __func__, drv->ap_oper_freq);
- return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0,
- data, data_len, &drv->send_action_cookie);
+#ifdef ANDROID_P2P
+ if (is_ap_interface(drv->nlmode)) {
+ return nl80211_send_frame_cmd(bss, bss->freq, 0,
+ data, data_len, &drv->send_action_cookie, 0, noack, 1);
}
#else
- if (drv->no_monitor_iface_capab && drv->nlmode == NL80211_IFTYPE_AP ) {
- return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0,
- data, data_len, NULL);
+
+ if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
+ return nl80211_send_frame_cmd(bss, bss->freq, 0,
+ data, data_len, NULL,
+ 0, noack, 0);
}
#endif
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@@ -3777,15 +5239,59 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
encrypt = 0;
}
- wpa_printf(MSG_DEBUG, "%s: Sending frame using monitor interface/l2 socket", __func__);
- return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
+
+ return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
+ noack);
}
-static int wpa_driver_nl80211_set_beacon(void *priv,
- const u8 *head, size_t head_len,
- const u8 *tail, size_t tail_len,
- int dtim_period, int beacon_int)
+static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
+ int slot, int ht_opmode, int ap_isolate,
+ int *basic_rates)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
+
+ if (cts >= 0)
+ NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
+ if (preamble >= 0)
+ NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
+ if (slot >= 0)
+ NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
+ if (ht_opmode >= 0)
+ NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
+ if (ap_isolate >= 0)
+ NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
+
+ if (basic_rates) {
+ u8 rates[NL80211_MAX_SUPP_RATES];
+ u8 rates_len = 0;
+ int i;
+
+ for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
+ i++)
+ rates[rates_len++] = basic_rates[i] / 5;
+
+ NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_ap(void *priv,
+ struct wpa_driver_ap_params *params)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -3794,6 +5300,10 @@ static int wpa_driver_nl80211_set_beacon(void *priv,
int ret;
int beacon_set;
int ifindex = if_nametoindex(bss->ifname);
+ int num_suites;
+ u32 suites[10];
+ u32 ver;
+
beacon_set = bss->beacon_set;
msg = nlmsg_alloc();
@@ -3805,13 +5315,112 @@ static int wpa_driver_nl80211_set_beacon(void *priv,
if (beacon_set)
cmd = NL80211_CMD_SET_BEACON;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, cmd, 0);
- NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head);
- NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
+ nl80211_cmd(drv, msg, 0, cmd);
+ NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
+ NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, beacon_int);
- NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
+ NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid);
+ if (params->proberesp && params->proberesp_len)
+ NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
+ params->proberesp);
+ switch (params->hide_ssid) {
+ case NO_SSID_HIDING:
+ NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_NOT_IN_USE);
+ break;
+ case HIDDEN_SSID_ZERO_LEN:
+ NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_ZERO_LEN);
+ break;
+ case HIDDEN_SSID_ZERO_CONTENTS:
+ NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_ZERO_CONTENTS);
+ break;
+ }
+ if (params->privacy)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+ if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
+ (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
+ /* Leave out the attribute */
+ } else if (params->auth_algs & WPA_AUTH_ALG_SHARED)
+ NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
+ NL80211_AUTHTYPE_SHARED_KEY);
+ else
+ NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
+ NL80211_AUTHTYPE_OPEN_SYSTEM);
+
+ ver = 0;
+ if (params->wpa_version & WPA_PROTO_WPA)
+ ver |= NL80211_WPA_VERSION_1;
+ if (params->wpa_version & WPA_PROTO_RSN)
+ ver |= NL80211_WPA_VERSION_2;
+ if (ver)
+ NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+
+ num_suites = 0;
+ if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
+ suites[num_suites++] = WLAN_AKM_SUITE_8021X;
+ if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
+ suites[num_suites++] = WLAN_AKM_SUITE_PSK;
+ if (num_suites) {
+ NLA_PUT(msg, NL80211_ATTR_AKM_SUITES,
+ num_suites * sizeof(u32), suites);
+ }
+
+ if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
+ params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
+ NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
+
+ num_suites = 0;
+ if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
+ suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+ if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
+ suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
+ if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
+ suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
+ if (params->pairwise_ciphers & WPA_CIPHER_WEP40)
+ suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
+ if (num_suites) {
+ NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ num_suites * sizeof(u32), suites);
+ }
+
+ switch (params->group_cipher) {
+ case WPA_CIPHER_CCMP:
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+ WLAN_CIPHER_SUITE_CCMP);
+ break;
+ case WPA_CIPHER_TKIP:
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+ WLAN_CIPHER_SUITE_TKIP);
+ break;
+ case WPA_CIPHER_WEP104:
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+ WLAN_CIPHER_SUITE_WEP104);
+ break;
+ case WPA_CIPHER_WEP40:
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+ WLAN_CIPHER_SUITE_WEP40);
+ break;
+ }
+
+ if (params->beacon_ies) {
+ NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
+ wpabuf_head(params->beacon_ies));
+ }
+ if (params->proberesp_ies) {
+ NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
+ wpabuf_len(params->proberesp_ies),
+ wpabuf_head(params->proberesp_ies));
+ }
+ if (params->assocresp_ies) {
+ NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
+ wpabuf_len(params->assocresp_ies),
+ wpabuf_head(params->assocresp_ies));
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
@@ -3819,29 +5428,36 @@ static int wpa_driver_nl80211_set_beacon(void *priv,
ret, strerror(-ret));
} else {
bss->beacon_set = 1;
+ nl80211_set_bss(bss, params->cts_protect, params->preamble,
+ params->short_slot_time, params->ht_opmode,
+ params->isolate, params->basic_rates);
}
-#if defined(ANDROID_BRCM_P2P_PATCH) && defined(HOSTAPD)
+#if defined(ANDROID_P2P) && defined(HOSTAPD)
wpa_driver_nl80211_probe_req_report(priv, 1);
#endif
return ret;
nla_put_failure:
+ nlmsg_free(msg);
return -ENOBUFS;
}
-static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
int freq, int ht_enabled,
int sec_channel_offset)
{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
+ wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d "
+ "sec_channel_offset=%d)",
+ freq, ht_enabled, sec_channel_offset);
msg = nlmsg_alloc();
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_SET_WIPHY, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
@@ -3856,7 +5472,7 @@ static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
NL80211_CHAN_HT40PLUS);
break;
default:
-#ifndef ANDROID_BRCM_P2P_PATCH
+#ifndef ANDROID_P2P
/* Should be change to HT20 as a default value because P2P firmware does not support 11n for BCM4329 */
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
NL80211_CHAN_HT20);
@@ -3869,50 +5485,102 @@ static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- if (ret == 0)
+ msg = NULL;
+ if (ret == 0) {
+ bss->freq = freq;
return 0;
+ }
wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
"%d (%s)", freq, ret, strerror(-ret));
nla_put_failure:
+ nlmsg_free(msg);
return -1;
}
+static u32 sta_flags_nl80211(int flags)
+{
+ u32 f = 0;
+
+ if (flags & WPA_STA_AUTHORIZED)
+ f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
+ if (flags & WPA_STA_WMM)
+ f |= BIT(NL80211_STA_FLAG_WME);
+ if (flags & WPA_STA_SHORT_PREAMBLE)
+ f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
+ if (flags & WPA_STA_MFP)
+ f |= BIT(NL80211_STA_FLAG_MFP);
+ if (flags & WPA_STA_TDLS_PEER)
+ f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+
+ return f;
+}
+
+
static int wpa_driver_nl80211_sta_add(void *priv,
struct hostapd_sta_add_params *params)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg;
+ struct nl_msg *msg, *wme = NULL;
+ struct nl80211_sta_flag_update upd;
int ret = -ENOBUFS;
+ if ((params->flags & WPA_STA_TDLS_PEER) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+ return -EOPNOTSUPP;
+
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_NEW_STATION, 0);
+ nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
+ NL80211_CMD_NEW_STATION);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
- NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
params->supp_rates);
- NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
- params->listen_interval);
+ if (!params->set) {
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+ params->listen_interval);
+ }
if (params->ht_capabilities) {
NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
sizeof(*params->ht_capabilities),
params->ht_capabilities);
}
+ os_memset(&upd, 0, sizeof(upd));
+ upd.mask = sta_flags_nl80211(params->flags);
+ upd.set = upd.mask;
+ NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+ if (params->flags & WPA_STA_WMM) {
+ wme = nlmsg_alloc();
+ if (!wme)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+ params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
+ NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
+ (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
+ WMM_QOSINFO_STA_SP_MASK);
+ nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
if (ret)
- wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
- "result: %d (%s)", ret, strerror(-ret));
+ wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
+ "result: %d (%s)", params->set ? "SET" : "NEW", ret,
+ strerror(-ret));
if (ret == -EEXIST)
ret = 0;
nla_put_failure:
+ nlmsg_free(wme);
+ nlmsg_free(msg);
return ret;
}
@@ -3928,8 +5596,7 @@ static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_DEL_STATION, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
if_nametoindex(bss->ifname));
@@ -3940,6 +5607,7 @@ static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
return 0;
return ret;
nla_put_failure:
+ nlmsg_free(msg);
return -ENOBUFS;
}
@@ -3951,26 +5619,46 @@ static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
-#ifdef HOSTAPD
/* stop listening for EAPOL on this interface */
del_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
msg = nlmsg_alloc();
if (!msg)
goto nla_put_failure;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_DEL_INTERFACE, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
return;
+ msg = NULL;
nla_put_failure:
+ nlmsg_free(msg);
wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
}
+static const char * nl80211_iftype_str(enum nl80211_iftype mode)
+{
+ switch (mode) {
+ case NL80211_IFTYPE_ADHOC:
+ return "ADHOC";
+ case NL80211_IFTYPE_STATION:
+ return "STATION";
+ case NL80211_IFTYPE_AP:
+ return "AP";
+ case NL80211_IFTYPE_MONITOR:
+ return "MONITOR";
+ case NL80211_IFTYPE_P2P_CLIENT:
+ return "P2P_CLIENT";
+ case NL80211_IFTYPE_P2P_GO:
+ return "P2P_GO";
+ default:
+ return "unknown";
+ }
+}
+
+
static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
const char *ifname,
enum nl80211_iftype iftype,
@@ -3980,12 +5668,14 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
int ifidx;
int ret = -ENOBUFS;
+ wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
+ iftype, nl80211_iftype_str(iftype));
+
msg = nlmsg_alloc();
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_NEW_INTERFACE, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
@@ -4010,8 +5700,10 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
if (ret) {
nla_put_failure:
+ nlmsg_free(msg);
wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
ifname, ret, strerror(-ret));
return ret;
@@ -4024,13 +5716,11 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
if (ifidx <= 0)
return -1;
-#ifdef HOSTAPD
/* start listening for EAPOL on this interface */
add_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
if (addr && iftype != NL80211_IFTYPE_MONITOR &&
- linux_set_ifhwaddr(drv->ioctl_sock, ifname, addr)) {
+ linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
nl80211_remove_iface(drv, ifidx);
return -1;
}
@@ -4047,7 +5737,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
- /* if error occured and interface exists already */
+ /* if error occurred and interface exists already */
if (ret == -ENFILE && if_nametoindex(ifname)) {
wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
@@ -4059,7 +5749,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
wds);
}
- if (ret >= 0 && drv->disable_11b_rates)
+ if (ret >= 0 && is_p2p_interface(iftype))
nl80211_disable_11b_rates(drv, ret, 1);
return ret;
@@ -4089,10 +5779,20 @@ static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
u8 *buf, size_t len)
{
+ struct ieee80211_hdr *hdr = (void *)buf;
+ u16 fc;
union wpa_event_data event;
+
+ if (len < sizeof(*hdr))
+ return;
+
+ fc = le_to_host16(hdr->frame_control);
+
os_memset(&event, 0, sizeof(event));
- event.rx_from_unknown.frame = buf;
- event.rx_from_unknown.len = len;
+ event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+ event.rx_from_unknown.addr = hdr->addr2;
+ event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
+ (WLAN_FC_FROMDS | WLAN_FC_TODS);
wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
}
@@ -4350,6 +6050,10 @@ static int add_monitor_filter(int s)
static void nl80211_remove_monitor_interface(
struct wpa_driver_nl80211_data *drv)
{
+ drv->monitor_refcount--;
+ if (drv->monitor_refcount > 0)
+ return;
+
if (drv->monitor_ifidx >= 0) {
nl80211_remove_iface(drv, drv->monitor_ifidx);
drv->monitor_ifidx = -1;
@@ -4369,11 +6073,25 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
struct sockaddr_ll ll;
int optval;
socklen_t optlen;
-#ifdef ANDROID_BRCM_P2P_PATCH
- snprintf(buf, IFNAMSIZ, "%s%s", WPA_MONITOR_IFNAME_PREFIX, drv->first_bss.ifname);
-#else
- snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
-#endif
+
+ if (drv->monitor_ifidx >= 0) {
+ drv->monitor_refcount++;
+ return 0;
+ }
+
+ if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
+ /*
+ * P2P interface name is of the format p2p-%s-%d. For monitor
+ * interface name corresponding to P2P GO, replace "p2p-" with
+ * "mon-" to retain the same interface name length and to
+ * indicate that it is a monitor interface.
+ */
+ snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
+ } else {
+ /* Non-P2P interface with AP functionality. */
+ snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
+ }
+
buf[IFNAMSIZ - 1] = '\0';
drv->monitor_ifidx =
@@ -4381,15 +6099,21 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
0);
if (drv->monitor_ifidx == -EOPNOTSUPP) {
+ /*
+ * This is backward compatibility for a few versions of
+ * the kernel only that didn't advertise the right
+ * attributes for the only driver that then supported
+ * AP mode w/o monitor -- ath6kl.
+ */
wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
"monitor interface type - try to run without it");
- drv->no_monitor_iface_capab = 1;
+ drv->device_ap_sme = 1;
}
if (drv->monitor_ifidx < 0)
return -1;
- if (linux_set_iface_flags(drv->ioctl_sock, buf, 1))
+ if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
goto error;
memset(&ll, 0, sizeof(ll));
@@ -4433,6 +6157,98 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
}
+static int nl80211_setup_ap(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
+ "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
+
+ /*
+ * Disable Probe Request reporting unless we need it in this way for
+ * devices that include the AP SME, in the other case (unless using
+ * monitor iface) we'll get it through the nl_mgmt socket instead.
+ */
+ if (!drv->device_ap_sme)
+ wpa_driver_nl80211_probe_req_report(bss, 0);
+
+ if (!drv->device_ap_sme && !drv->use_monitor)
+ if (nl80211_mgmt_subscribe_ap(bss))
+ return -1;
+
+ if (drv->device_ap_sme && !drv->use_monitor)
+ if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
+ return -1;
+
+ if (!drv->device_ap_sme && drv->use_monitor &&
+ nl80211_create_monitor_interface(drv) &&
+ !drv->device_ap_sme)
+ return -1;
+
+ if (drv->device_ap_sme &&
+ wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
+ "Probe Request frame reporting in AP mode");
+ /* Try to survive without this */
+ }
+
+#ifdef ANDROID_P2P
+ /* For AP mode, enable probe req report even if device_ap_sme
+ * is not enabled
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Enabling probe req report");
+ wpa_driver_nl80211_probe_req_report(bss, 1);
+#endif
+
+ return 0;
+}
+
+
+static void nl80211_teardown_ap(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (drv->device_ap_sme) {
+ wpa_driver_nl80211_probe_req_report(bss, 0);
+ if (!drv->use_monitor)
+ nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
+ } else if (drv->use_monitor)
+ nl80211_remove_monitor_interface(drv);
+ else
+ nl80211_mgmt_unsubscribe(bss, "AP teardown");
+
+ bss->beacon_set = 0;
+}
+
+
+static int nl80211_send_eapol_data(struct i802_bss *bss,
+ const u8 *addr, const u8 *data,
+ size_t data_len)
+{
+ struct sockaddr_ll ll;
+ int ret;
+
+ if (bss->drv->eapol_tx_sock < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
+ return -1;
+ }
+
+ os_memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = bss->ifindex;
+ ll.sll_protocol = htons(ETH_P_PAE);
+ ll.sll_halen = ETH_ALEN;
+ os_memcpy(ll.sll_addr, addr, ETH_ALEN);
+ ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
+ (struct sockaddr *) &ll, sizeof(ll));
+ if (ret < 0)
+ wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
+ strerror(errno));
+
+ return ret;
+}
+
+
static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
static int wpa_driver_nl80211_hapd_send_eapol(
@@ -4447,6 +6263,9 @@ static int wpa_driver_nl80211_hapd_send_eapol(
int res;
int qos = flags & WPA_STA_WMM;
+ if (drv->device_ap_sme || !drv->use_monitor)
+ return nl80211_send_eapol_data(bss, addr, data, data_len);
+
len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
data_len;
hdr = os_zalloc(len);
@@ -4484,7 +6303,7 @@ static int wpa_driver_nl80211_hapd_send_eapol(
pos += 2;
memcpy(pos, data, data_len);
- res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt);
+ res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0);
if (res < 0) {
wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
"failed: %d (%s)",
@@ -4496,23 +6315,6 @@ static int wpa_driver_nl80211_hapd_send_eapol(
}
-static u32 sta_flags_nl80211(int flags)
-{
- u32 f = 0;
-
- if (flags & WPA_STA_AUTHORIZED)
- f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
- if (flags & WPA_STA_WMM)
- f |= BIT(NL80211_STA_FLAG_WME);
- if (flags & WPA_STA_SHORT_PREAMBLE)
- f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
- if (flags & WPA_STA_MFP)
- f |= BIT(NL80211_STA_FLAG_MFP);
-
- return f;
-}
-
-
static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
int total_flags,
int flags_or, int flags_and)
@@ -4532,8 +6334,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
return -ENOMEM;
}
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_STATION, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
if_nametoindex(bss->ifname));
@@ -4555,6 +6356,9 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
if (total_flags & WPA_STA_MFP)
NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+ if (total_flags & WPA_STA_TDLS_PEER)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+
if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
goto nla_put_failure;
@@ -4567,6 +6371,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
return send_and_recv_msgs(drv, msg, NULL, NULL);
nla_put_failure:
+ nlmsg_free(msg);
nlmsg_free(flags);
return -ENOBUFS;
}
@@ -4575,20 +6380,21 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
{
- if (params->p2p)
+ enum nl80211_iftype nlmode;
+
+ if (params->p2p) {
wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
"group (GO)");
- if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) ||
- wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) {
+ nlmode = NL80211_IFTYPE_P2P_GO;
+ } else
+ nlmode = NL80211_IFTYPE_AP;
+
+ if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) ||
+ wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) {
nl80211_remove_monitor_interface(drv);
return -1;
}
- /* TODO: setup monitor interface (and add code somewhere to remove this
- * when AP mode is stopped; associate with mode != 2 or drv_deinit) */
- wpa_printf(MSG_DEBUG, "nl80211: Update ap_oper_freq with params->freq %d", params->freq);
- drv->ap_oper_freq = params->freq;
-
return 0;
}
@@ -4602,8 +6408,7 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_LEAVE_IBSS, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
@@ -4631,7 +6436,8 @@ static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
- if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) {
+ if (wpa_driver_nl80211_set_mode(&drv->first_bss,
+ NL80211_IFTYPE_ADHOC)) {
wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
"IBSS mode");
return -1;
@@ -4642,8 +6448,7 @@ retry:
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_JOIN_IBSS, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
@@ -4696,6 +6501,55 @@ nla_put_failure:
}
+static unsigned int nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv,
+ u8 *bssid)
+{
+ struct nl_msg *msg;
+ int ret;
+ struct nl80211_bss_info_arg arg;
+
+ os_memset(&arg, 0, sizeof(arg));
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ arg.drv = drv;
+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ msg = NULL;
+ if (ret == 0) {
+ if (is_zero_ether_addr(arg.assoc_bssid))
+ return -ENOTCONN;
+ os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN);
+ return 0;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+nla_put_failure:
+ nlmsg_free(msg);
+ return drv->assoc_freq;
+}
+
+
+static int nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
+ const u8 *bssid)
+{
+ u8 addr[ETH_ALEN];
+
+ if (bssid == NULL) {
+ int res = nl80211_get_assoc_bssid(drv, addr);
+ if (res)
+ return res;
+ bssid = addr;
+ }
+
+ return wpa_driver_nl80211_disconnect(drv, bssid,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+}
+
+
static int wpa_driver_nl80211_connect(
struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
@@ -4710,8 +6564,7 @@ static int wpa_driver_nl80211_connect(
return -1;
wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_CONNECT, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (params->bssid) {
@@ -4766,15 +6619,15 @@ static int wpa_driver_nl80211_connect(
NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
skip_auth_type:
- if (params->wpa_ie && params->wpa_ie_len) {
- enum nl80211_wpa_versions ver;
+ if (params->wpa_proto) {
+ enum nl80211_wpa_versions ver = 0;
- if (params->wpa_ie[0] == WLAN_EID_RSN)
- ver = NL80211_WPA_VERSION_2;
- else
- ver = NL80211_WPA_VERSION_1;
+ if (params->wpa_proto & WPA_PROTO_WPA)
+ ver |= NL80211_WPA_VERSION_1;
+ if (params->wpa_proto & WPA_PROTO_RSN)
+ ver |= NL80211_WPA_VERSION_2;
- wpa_printf(MSG_DEBUG, " * WPA Version %d", ver);
+ wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
}
@@ -4845,6 +6698,14 @@ skip_auth_type:
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
"(%s)", ret, strerror(-ret));
+ /*
+ * cfg80211 does not currently accept new connection if we are
+ * already connected. As a workaround, force disconnection and
+ * try again once the driver indicates it completed
+ * disconnection.
+ */
+ if (ret == -EALREADY)
+ nl80211_disconnect(drv, params->bssid);
goto nla_put_failure;
}
ret = 0;
@@ -4872,7 +6733,10 @@ static int wpa_driver_nl80211_associate(
return wpa_driver_nl80211_ibss(drv, params);
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
- if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0)
+ enum nl80211_iftype nlmode = params->p2p ?
+ NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+
+ if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
return wpa_driver_nl80211_connect(drv, params);
}
@@ -4885,8 +6749,7 @@ static int wpa_driver_nl80211_associate(
wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
drv->ifindex);
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_ASSOCIATE, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (params->bssid) {
@@ -4979,8 +6842,9 @@ static int wpa_driver_nl80211_associate(
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
- "(%s)", ret, strerror(-ret));
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: MLME command failed (assoc): ret=%d (%s)",
+ ret, strerror(-ret));
nl80211_dump_scan(drv);
goto nla_put_failure;
}
@@ -4995,58 +6859,53 @@ nla_put_failure:
static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
- int ifindex, int mode)
+ int ifindex, enum nl80211_iftype mode)
{
struct nl_msg *msg;
int ret = -ENOBUFS;
+ wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
+ ifindex, mode, nl80211_iftype_str(mode));
+
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_INTERFACE, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
if (!ret)
return 0;
nla_put_failure:
+ nlmsg_free(msg);
wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
" %d (%s)", ifindex, mode, ret, strerror(-ret));
return ret;
}
-static int wpa_driver_nl80211_set_mode(void *priv, int mode)
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+ enum nl80211_iftype nlmode)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
- int nlmode;
int i;
+ int was_ap = is_ap_interface(drv->nlmode);
+ int res;
- switch (mode) {
- case 0:
- nlmode = NL80211_IFTYPE_STATION;
- break;
- case 1:
- nlmode = NL80211_IFTYPE_ADHOC;
- break;
- case 2:
- nlmode = NL80211_IFTYPE_AP;
- break;
- default:
- return -1;
- }
-
- if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) {
+ res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+ if (res == 0) {
drv->nlmode = nlmode;
ret = 0;
goto done;
}
+ if (res == -ENODEV)
+ return -1;
+
if (nlmode == drv->nlmode) {
wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
"requested mode - ignore error");
@@ -5061,15 +6920,21 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode)
wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
"interface down");
for (i = 0; i < 10; i++) {
- if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) ==
- 0) {
+ res = linux_set_iface_flags(drv->global->ioctl_sock,
+ bss->ifname, 0);
+ if (res == -EACCES || res == -ENODEV)
+ break;
+ if (res == 0) {
/* Try to set the mode again while the interface is
* down */
ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
- if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname,
- 1))
+ if (ret == -EACCES)
+ break;
+ res = linux_set_iface_flags(drv->global->ioctl_sock,
+ bss->ifname, 1);
+ if (res && !ret)
ret = -1;
- if (!ret)
+ else if (ret != -EBUSY)
break;
} else
wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
@@ -5081,26 +6946,34 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode)
wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
"interface is down");
drv->nlmode = nlmode;
+ drv->ignore_if_down_event = 1;
}
done:
- if (!ret && nlmode == NL80211_IFTYPE_AP) {
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
+ "from %d failed", nlmode, drv->nlmode);
+ return ret;
+ }
+
+ if (is_ap_interface(nlmode)) {
+ nl80211_mgmt_unsubscribe(bss, "start AP");
/* Setup additional AP mode functionality if needed */
- if (!drv->no_monitor_iface_capab && drv->monitor_ifidx < 0 &&
- nl80211_create_monitor_interface(drv) &&
- !drv->no_monitor_iface_capab)
+ if (nl80211_setup_ap(bss))
return -1;
- } else if (!ret && nlmode != NL80211_IFTYPE_AP) {
+ } else if (was_ap) {
/* Remove additional AP mode functionality */
- nl80211_remove_monitor_interface(drv);
- bss->beacon_set = 0;
+ nl80211_teardown_ap(bss);
+ } else {
+ nl80211_mgmt_unsubscribe(bss, "mode change");
}
- if (ret)
- wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
- "from %d failed", nlmode, drv->nlmode);
+ if (!is_ap_interface(nlmode) &&
+ nl80211_mgmt_subscribe_non_ap(bss) < 0)
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
+ "frame processing - ignore for now");
- return ret;
+ return 0;
}
@@ -5124,7 +6997,7 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state)
wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
__func__, drv->operstate, state, state ? "UP" : "DORMANT");
drv->operstate = state;
- return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
+ return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
state ? IF_OPER_UP : IF_OPER_DORMANT);
}
@@ -5140,8 +7013,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_STATION, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
if_nametoindex(bss->ifname));
@@ -5155,6 +7027,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
return send_and_recv_msgs(drv, msg, NULL, NULL);
nla_put_failure:
+ nlmsg_free(msg);
return -ENOBUFS;
}
@@ -5163,8 +7036,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
{
struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
+ return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled,
freq->sec_channel_offset);
}
@@ -5211,8 +7083,7 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_GET_KEY, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
if (addr)
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
@@ -5223,36 +7094,7 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
return send_and_recv_msgs(drv, msg, get_key_handler, seq);
nla_put_failure:
- return -ENOBUFS;
-}
-
-
-static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
- int mode)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg;
- u8 rates[NL80211_MAX_SUPP_RATES];
- u8 rates_len = 0;
- int i;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_SET_BSS, 0);
-
- for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
- rates[rates_len++] = basic_rates[i] / 5;
-
- NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
- return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
+ nlmsg_free(msg);
return -ENOBUFS;
}
@@ -5274,15 +7116,16 @@ static int i802_set_rts(void *priv, int rts)
else
val = rts;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_WIPHY, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
if (!ret)
return 0;
nla_put_failure:
+ nlmsg_free(msg);
wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
"%d (%s)", rts, ret, strerror(-ret));
return ret;
@@ -5306,15 +7149,16 @@ static int i802_set_frag(void *priv, int frag)
else
val = frag;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_WIPHY, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
if (!ret)
return 0;
nla_put_failure:
+ nlmsg_free(msg);
wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
"%d: %d (%s)", frag, ret, strerror(-ret));
return ret;
@@ -5326,13 +7170,13 @@ static int i802_flush(void *priv)
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
+ int res;
msg = nlmsg_alloc();
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_DEL_STATION, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
/*
* XXX: FIX! this needs to flush all VLANs too
@@ -5340,8 +7184,14 @@ static int i802_flush(void *priv)
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
if_nametoindex(bss->ifname));
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ res = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
+ "(%s)", res, strerror(-res));
+ }
+ return res;
nla_put_failure:
+ nlmsg_free(msg);
return -ENOBUFS;
}
@@ -5409,14 +7259,14 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_GET_STATION, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
return send_and_recv_msgs(drv, msg, get_sta_handler, data);
nla_put_failure:
+ nlmsg_free(msg);
return -ENOBUFS;
}
@@ -5433,8 +7283,7 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_WIPHY, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
@@ -5474,59 +7323,13 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
return 0;
+ msg = NULL;
nla_put_failure:
+ nlmsg_free(msg);
return -1;
}
-static int i802_set_bss(void *priv, int cts, int preamble, int slot,
- int ht_opmode)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_SET_BSS, 0);
-
- if (cts >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
- if (preamble >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
- if (slot >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
- if (ht_opmode >= 0)
- NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
- return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
- return -ENOBUFS;
-}
-
-
-static int i802_set_cts_protect(void *priv, int value)
-{
- return i802_set_bss(priv, value, -1, -1, -1);
-}
-
-
-static int i802_set_preamble(void *priv, int value)
-{
- return i802_set_bss(priv, -1, value, -1, -1);
-}
-
-
-static int i802_set_short_slot_time(void *priv, int value)
-{
- return i802_set_bss(priv, -1, -1, value, -1);
-}
-
-
static int i802_set_sta_vlan(void *priv, const u8 *addr,
const char *ifname, int vlan_id)
{
@@ -5539,8 +7342,7 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr,
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_STATION, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
if_nametoindex(bss->ifname));
@@ -5549,6 +7351,7 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr,
if_nametoindex(ifname));
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
@@ -5556,23 +7359,11 @@ static int i802_set_sta_vlan(void *priv, const u8 *addr,
strerror(-ret));
}
nla_put_failure:
+ nlmsg_free(msg);
return ret;
}
-static int i802_set_ht_params(void *priv, const u8 *ht_capab,
- size_t ht_capab_len, const u8 *ht_oper,
- size_t ht_oper_len)
-{
- if (ht_oper_len >= 6) {
- /* ht opmode uses 16bit in octet 5 & 6 */
- u16 ht_opmode = le_to_host16(((u16 *) ht_oper)[2]);
- return i802_set_bss(priv, -1, -1, -1, ht_opmode);
- } else
- return -1;
-}
-
-
static int i802_get_inact_sec(void *priv, const u8 *addr)
{
struct hostap_sta_driver_data data;
@@ -5610,7 +7401,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
mgmt.u.deauth.reason_code = host_to_le16(reason);
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth));
+ sizeof(mgmt.u.deauth), 0);
}
@@ -5629,7 +7420,7 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
mgmt.u.disassoc.reason_code = host_to_le16(reason);
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
- sizeof(mgmt.u.disassoc));
+ sizeof(mgmt.u.disassoc), 0);
}
#endif /* HOSTAPD || CONFIG_AP */
@@ -5716,11 +7507,11 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
NULL, 1) < 0)
return -1;
if (bridge_ifname &&
- linux_br_add_if(drv->ioctl_sock, bridge_ifname,
- name) < 0)
+ linux_br_add_if(drv->global->ioctl_sock,
+ bridge_ifname, name) < 0)
return -1;
}
- linux_set_iface_flags(drv->ioctl_sock, name, 1);
+ linux_set_iface_flags(drv->global->ioctl_sock, name, 1);
return i802_set_sta_vlan(priv, addr, name, 0);
} else {
i802_set_sta_vlan(priv, addr, bss->ifname, 0);
@@ -5764,7 +7555,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
* Bridge was configured, but the bridge device does
* not exist. Try to add it now.
*/
- if (linux_br_add(drv->ioctl_sock, brname) < 0) {
+ if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
"bridge interface %s: %s",
brname, strerror(errno));
@@ -5780,7 +7571,8 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
"bridge %s", ifname, in_br);
- if (linux_br_del_if(drv->ioctl_sock, in_br, ifname) < 0) {
+ if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
+ 0) {
wpa_printf(MSG_ERROR, "nl80211: Failed to "
"remove interface %s from bridge "
"%s: %s",
@@ -5791,7 +7583,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
ifname, brname);
- if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) {
+ if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
"into bridge %s: %s",
ifname, brname, strerror(errno));
@@ -5813,12 +7605,15 @@ static void *i802_init(struct hostapd_data *hapd,
int ifindex, br_ifindex;
int br_added = 0;
- bss = wpa_driver_nl80211_init(hapd, params->ifname, NULL);
+ bss = wpa_driver_nl80211_init(hapd, params->ifname,
+ params->global_priv);
if (bss == NULL)
return NULL;
drv = bss->drv;
drv->nlmode = NL80211_IFTYPE_AP;
+ drv->eapol_sock = -1;
+
if (linux_br_get(brname, params->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
params->ifname, brname);
@@ -5846,16 +7641,16 @@ static void *i802_init(struct hostapd_data *hapd,
/* start listening for EAPOL on the default AP interface */
add_ifidx(drv, drv->ifindex);
- if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0))
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
goto failed;
if (params->bssid) {
- if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname,
+ if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
params->bssid))
goto failed;
}
- if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) {
+ if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
"into AP mode", bss->ifname);
goto failed;
@@ -5865,7 +7660,7 @@ static void *i802_init(struct hostapd_data *hapd,
i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
goto failed;
- if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
goto failed;
drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
@@ -5880,25 +7675,16 @@ static void *i802_init(struct hostapd_data *hapd,
goto failed;
}
- if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr))
+ if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+ params->own_addr))
goto failed;
+ memcpy(bss->addr, params->own_addr, ETH_ALEN);
+
return bss;
failed:
- nl80211_remove_monitor_interface(drv);
- rfkill_deinit(drv->rfkill);
- netlink_deinit(drv->netlink);
- if (drv->ioctl_sock >= 0)
- close(drv->ioctl_sock);
-
- genl_family_put(drv->nl80211);
- nl_cache_free(drv->nl_cache);
- nl80211_handle_destroy(drv->nl_handle);
- nl_cb_put(drv->nl_cb);
- eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-
- os_free(drv);
+ wpa_driver_nl80211_deinit(bss);
return NULL;
}
@@ -5938,7 +7724,7 @@ static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
struct wpa_driver_nl80211_data *drv;
dl_list_for_each(drv, &global->interfaces,
struct wpa_driver_nl80211_data, list) {
- if (os_memcmp(addr, drv->addr, ETH_ALEN) == 0)
+ if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
return 1;
}
return 0;
@@ -5953,9 +7739,9 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
if (!drv->global)
return -1;
- os_memcpy(new_addr, drv->addr, ETH_ALEN);
+ os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
for (idx = 0; idx < 64; idx++) {
- new_addr[0] = drv->addr[0] | 0x02;
+ new_addr[0] = drv->first_bss.addr[0] | 0x02;
new_addr[0] ^= idx << 2;
if (!nl80211_addr_in_use(drv->global, new_addr))
break;
@@ -6004,7 +7790,8 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
}
if (!addr &&
- linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0) {
+ linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+ if_addr) < 0) {
nl80211_remove_iface(drv, ifidx);
return -1;
}
@@ -6016,10 +7803,10 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
/* Enforce unique P2P Interface Address */
u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
- if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr)
- < 0 ||
- linux_get_ifhwaddr(drv->ioctl_sock, ifname, new_addr) < 0)
- {
+ if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+ own_addr) < 0 ||
+ linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+ new_addr) < 0) {
nl80211_remove_iface(drv, ifidx);
return -1;
}
@@ -6030,7 +7817,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
nl80211_remove_iface(drv, ifidx);
return -1;
}
- if (linux_set_ifhwaddr(drv->ioctl_sock, ifname,
+ if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
new_addr) < 0) {
nl80211_remove_iface(drv, ifidx);
return -1;
@@ -6051,21 +7838,27 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
}
if (type == WPA_IF_AP_BSS) {
- if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) {
+ if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
+ {
nl80211_remove_iface(drv, ifidx);
os_free(new_bss);
return -1;
}
os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
+ os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
new_bss->ifindex = ifidx;
new_bss->drv = drv;
new_bss->next = drv->first_bss.next;
drv->first_bss.next = new_bss;
if (drv_priv)
*drv_priv = new_bss;
+ nl80211_init_bss(new_bss);
}
#endif /* HOSTAPD */
+ if (drv->global)
+ drv->global->if_add_ifindex = ifidx;
+
return 0;
}
@@ -6085,14 +7878,14 @@ static int wpa_driver_nl80211_if_remove(void *priv,
#ifdef HOSTAPD
if (bss->added_if_into_bridge) {
- if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
- < 0)
+ if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+ bss->ifname) < 0)
wpa_printf(MSG_INFO, "nl80211: Failed to remove "
"interface %s from bridge %s: %s",
bss->ifname, bss->brname, strerror(errno));
}
if (bss->added_bridge) {
- if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
+ if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
wpa_printf(MSG_INFO, "nl80211: Failed to remove "
"bridge %s: %s",
bss->brname, strerror(errno));
@@ -6111,6 +7904,7 @@ static int wpa_driver_nl80211_if_remove(void *priv,
for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
if (tbss->next == bss) {
tbss->next = bss->next;
+ nl80211_destroy_bss(bss);
os_free(bss);
bss = NULL;
break;
@@ -6139,11 +7933,13 @@ static int cookie_handler(struct nl_msg *msg, void *arg)
}
-static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
+static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait,
const u8 *buf, size_t buf_len,
- u64 *cookie_out)
+ u64 *cookie_out, int no_cck, int no_ack,
+ int offchanok)
{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
u64 cookie;
int ret = -1;
@@ -6152,16 +7948,21 @@ static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_FRAME, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-#ifndef ANDROID_BRCM_P2P_PATCH
+#ifndef ANDROID_P2P
if (wait)
NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
#endif
- NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
+ if (offchanok)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
+ if (no_cck)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
+ if (no_ack)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
+
NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
cookie = 0;
@@ -6173,11 +7974,12 @@ static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
freq, wait);
goto nla_put_failure;
}
- wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted; "
- "cookie 0x%llx", (long long unsigned int) cookie);
+ wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
+ "cookie 0x%llx", no_ack ? " (no ACK)" : "",
+ (long long unsigned int) cookie);
if (cookie_out)
- *cookie_out = cookie;
+ *cookie_out = no_ack ? (u64) -1 : cookie;
nla_put_failure:
nlmsg_free(msg);
@@ -6189,7 +7991,8 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
unsigned int wait_time,
const u8 *dst, const u8 *src,
const u8 *bssid,
- const u8 *data, size_t data_len)
+ const u8 *data, size_t data_len,
+ int no_cck)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -6198,7 +8001,7 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
struct ieee80211_hdr *hdr;
wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
- "wait=%d ms)", drv->ifindex, wait_time);
+ "wait=%d ms no_cck=%d)", drv->ifindex, wait_time, no_cck);
buf = os_zalloc(24 + data_len);
if (buf == NULL)
@@ -6211,12 +8014,14 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
os_memcpy(hdr->addr2, src, ETH_ALEN);
os_memcpy(hdr->addr3, bssid, ETH_ALEN);
- if (drv->nlmode == NL80211_IFTYPE_AP)
- ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len);
+ if (is_ap_interface(drv->nlmode))
+ ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len,
+ 0);
else
- ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf,
+ ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
24 + data_len,
- &drv->send_action_cookie);
+ &drv->send_action_cookie,
+ no_cck, 0, 1);
os_free(buf);
return ret;
@@ -6234,8 +8039,7 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
if (!msg)
return;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_FRAME_WAIT_CANCEL, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
@@ -6264,8 +8068,7 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_REMAIN_ON_CHANNEL, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
@@ -6273,17 +8076,20 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
cookie = 0;
ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+ msg = NULL;
if (ret == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
"0x%llx for freq=%u MHz duration=%u",
(long long unsigned int) cookie, freq, duration);
drv->remain_on_chan_cookie = cookie;
+ drv->pending_remain_on_chan = 1;
return 0;
}
wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
"(freq=%d duration=%u): %d (%s)",
freq, duration, ret, strerror(-ret));
nla_put_failure:
+ nlmsg_free(msg);
return -1;
}
@@ -6309,18 +8115,19 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
if (ret == 0)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
"%d (%s)", ret, strerror(-ret));
nla_put_failure:
+ nlmsg_free(msg);
return -1;
}
@@ -6331,60 +8138,43 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
struct wpa_driver_nl80211_data *drv = bss->drv;
if (!report) {
- if (drv->nl_handle_preq) {
+ if (bss->nl_preq && drv->device_ap_sme &&
+ is_ap_interface(drv->nlmode)) {
+ /*
+ * Do not disable Probe Request reporting that was
+ * enabled in nl80211_setup_ap().
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
+ "Probe Request reporting nl_preq=%p while "
+ "in AP mode", bss->nl_preq);
+ } else if (bss->nl_preq) {
+ wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
+ "reporting nl_preq=%p", bss->nl_preq);
eloop_unregister_read_sock(
- nl_socket_get_fd(drv->nl_handle_preq));
- nl_cache_free(drv->nl_cache_preq);
- nl80211_handle_destroy(drv->nl_handle_preq);
- drv->nl_handle_preq = NULL;
+ nl_socket_get_fd(bss->nl_preq));
+ nl_destroy_handles(&bss->nl_preq);
}
return 0;
}
- if (drv->nl_handle_preq) {
+ if (bss->nl_preq) {
wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
- "already on!");
+ "already on! nl_preq=%p", bss->nl_preq);
return 0;
}
- drv->nl_handle_preq = nl80211_handle_alloc(drv->nl_cb);
- if (drv->nl_handle_preq == NULL) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate "
- "netlink callbacks (preq)");
- goto out_err1;
- }
-
- if (genl_connect(drv->nl_handle_preq)) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to connect to "
- "generic netlink (preq)");
- goto out_err2;
+ bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
+ if (bss->nl_preq == NULL)
return -1;
- }
+ wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
+ "reporting nl_preq=%p", bss->nl_preq);
-#ifdef CONFIG_LIBNL20
- if (genl_ctrl_alloc_cache(drv->nl_handle_preq,
- &drv->nl_cache_preq) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
- "netlink cache (preq)");
- goto out_err2;
- }
-#else /* CONFIG_LIBNL20 */
- drv->nl_cache_preq = genl_ctrl_alloc_cache(drv->nl_handle_preq);
- if (drv->nl_cache_preq == NULL) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
- "netlink cache (preq)");
- goto out_err2;
- }
-#endif /* CONFIG_LIBNL20 */
-
- if (nl80211_register_frame(drv, drv->nl_handle_preq,
+ if (nl80211_register_frame(bss, bss->nl_preq,
(WLAN_FC_TYPE_MGMT << 2) |
(WLAN_FC_STYPE_PROBE_REQ << 4),
- NULL, 0) < 0) {
- goto out_err3;
- }
-
-#ifdef ANDROID_BRCM_P2P_PATCH
+ NULL, 0) < 0)
+ goto out_err;
+#ifdef ANDROID_P2P
if (drv->nlmode != NL80211_IFTYPE_AP &&
drv->nlmode != NL80211_IFTYPE_P2P_GO) {
wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
@@ -6392,49 +8182,51 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
drv->nlmode);
goto done;
}
-
- if (nl80211_register_frame(drv, drv->nl_handle_preq,
+ if (nl80211_register_frame(bss, bss->nl_preq,
(WLAN_FC_TYPE_MGMT << 2) |
(WLAN_FC_STYPE_ASSOC_REQ << 4),
NULL, 0) < 0) {
- goto out_err3;
+ goto out_err;
}
- if (nl80211_register_frame(drv, drv->nl_handle_preq,
+ if (nl80211_register_frame(bss, bss->nl_preq,
(WLAN_FC_TYPE_MGMT << 2) |
(WLAN_FC_STYPE_REASSOC_REQ << 4),
NULL, 0) < 0) {
- goto out_err3;
+ goto out_err;
}
- if (nl80211_register_frame(drv, drv->nl_handle_preq,
+ if (nl80211_register_frame(bss, bss->nl_preq,
(WLAN_FC_TYPE_MGMT << 2) |
(WLAN_FC_STYPE_DISASSOC << 4),
NULL, 0) < 0) {
- goto out_err3;
+ goto out_err;
}
-
- if (nl80211_register_frame(drv, drv->nl_handle_preq,
+
+ if (nl80211_register_frame(bss, bss->nl_preq,
(WLAN_FC_TYPE_MGMT << 2) |
(WLAN_FC_STYPE_DEAUTH << 4),
NULL, 0) < 0) {
- goto out_err3;
+ goto out_err;
+ }
+
+ if (nl80211_register_frame(bss, bss->nl_preq,
+ (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_ACTION << 4),
+ NULL, 0) < 0) {
+ goto out_err;
}
done:
-#endif
- eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_preq),
- wpa_driver_nl80211_event_receive, drv,
- drv->nl_handle_preq);
+#endif /* ANDROID_P2P */
+ eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
+ wpa_driver_nl80211_event_receive, bss->nl_cb,
+ bss->nl_preq);
return 0;
- out_err3:
- nl_cache_free(drv->nl_cache_preq);
- out_err2:
- nl80211_handle_destroy(drv->nl_handle_preq);
- drv->nl_handle_preq = NULL;
- out_err1:
+ out_err:
+ nl_destroy_handles(&bss->nl_preq);
return -1;
}
@@ -6450,8 +8242,7 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_SET_TX_BITRATE_MASK, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
@@ -6466,8 +8257,10 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
band = nla_nest_start(msg, NL80211_BAND_2GHZ);
if (!band)
goto nla_put_failure;
- NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
- "\x0c\x12\x18\x24\x30\x48\x60\x6c");
+ if (disabled) {
+ NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
+ "\x0c\x12\x18\x24\x30\x48\x60\x6c");
+ }
nla_nest_end(msg, band);
nla_nest_end(msg, bands);
@@ -6487,23 +8280,14 @@ nla_put_failure:
}
-static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- drv->disable_11b_rates = disabled;
- return nl80211_disable_11b_rates(drv, drv->ifindex, disabled);
-}
-
-
static int wpa_driver_nl80211_deinit_ap(void *priv)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- if (drv->nlmode != NL80211_IFTYPE_AP)
+ if (!is_ap_interface(drv->nlmode))
return -1;
wpa_driver_nl80211_del_beacon(drv);
- return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
+ return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
}
@@ -6511,7 +8295,7 @@ 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->ioctl_sock, bss->ifname, 1)) {
+ 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");
}
@@ -6526,10 +8310,7 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
int ret;
u8 *data, *pos;
size_t data_len;
- u8 own_addr[ETH_ALEN];
-
- if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0)
- return -1;
+ const u8 *own_addr = bss->addr;
if (action != 1) {
wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
@@ -6561,7 +8342,7 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
drv->bssid, own_addr, drv->bssid,
- data, data_len);
+ data, data_len, 0);
os_free(data);
return ret;
@@ -6581,8 +8362,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
if (!msg)
return -1;
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
- 0, NL80211_CMD_SET_CQM, 0);
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
@@ -6599,8 +8379,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
msg = NULL;
nla_put_failure:
- if (cqm)
- nlmsg_free(cqm);
+ nlmsg_free(cqm);
nlmsg_free(msg);
return -1;
}
@@ -6621,34 +8400,58 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
}
-static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
- int encrypt)
+static int wpa_driver_nl80211_shared_freq(void *priv)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
-}
+ struct wpa_driver_nl80211_data *driver;
+ int freq = 0;
+ /*
+ * If the same PHY is in connected state with some other interface,
+ * then retrieve the assoc freq.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
+ drv->phyname);
-static int nl80211_set_intra_bss(void *priv, int enabled)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg;
+ dl_list_for_each(driver, &drv->global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ if (drv == driver ||
+ os_strcmp(drv->phyname, driver->phyname) != 0 ||
+#ifdef ANDROID_P2P
+ (!driver->associated && !is_ap_interface(driver->nlmode)))
+#else
+ !driver->associated)
+#endif
+ continue;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
+ wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
+ MACSTR,
+ driver->phyname, driver->first_bss.ifname,
+ MAC2STR(driver->first_bss.addr));
+#ifdef ANDROID_P2P
+ if(is_ap_interface(driver->nlmode))
+ freq = driver->first_bss.freq;
+ else
+#endif
+ freq = nl80211_get_assoc_freq(driver);
+ wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
+ drv->phyname, freq);
+ }
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_SET_BSS, 0);
+ if (!freq)
+ wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
+ "PHY (%s) in associated state", drv->phyname);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
- NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, !enabled);
+ return freq;
+}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
- return -ENOBUFS;
+
+static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
+ int encrypt)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0);
}
@@ -6668,6 +8471,15 @@ 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;
}
+#ifdef ANDROID_P2P
+ if(os_strstr(param, "use_multi_chan_concurrent=1")) {
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel "
+ "concurrency");
+ drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+ }
+#endif
#endif /* CONFIG_P2P */
return 0;
@@ -6677,11 +8489,42 @@ static int nl80211_set_param(void *priv, const char *param)
static void * nl80211_global_init(void)
{
struct nl80211_global *global;
+ struct netlink_config *cfg;
+
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
+ global->ioctl_sock = -1;
dl_list_init(&global->interfaces);
+ global->if_add_ifindex = -1;
+
+ cfg = os_zalloc(sizeof(*cfg));
+ if (cfg == NULL)
+ goto err;
+
+ cfg->ctx = global;
+ cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
+ cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
+ global->netlink = netlink_init(cfg);
+ if (global->netlink == NULL) {
+ os_free(cfg);
+ goto err;
+ }
+
+ if (wpa_driver_nl80211_init_nl_global(global) < 0)
+ goto err;
+
+ global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (global->ioctl_sock < 0) {
+ perror("socket(PF_INET,SOCK_DGRAM)");
+ goto err;
+ }
+
return global;
+
+err:
+ nl80211_global_deinit(global);
+ return NULL;
}
@@ -6695,6 +8538,23 @@ static void nl80211_global_deinit(void *priv)
"nl80211_global_deinit",
dl_list_len(&global->interfaces));
}
+
+ if (global->netlink)
+ netlink_deinit(global->netlink);
+
+ nl_destroy_handles(&global->nl);
+
+ if (global->nl_event) {
+ eloop_unregister_read_sock(
+ nl_socket_get_fd(global->nl_event));
+ nl_destroy_handles(&global->nl_event);
+ }
+
+ nl_cb_put(global->nl_cb);
+
+ if (global->ioctl_sock >= 0)
+ close(global->ioctl_sock);
+
os_free(global);
}
@@ -6716,8 +8576,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_family_get_id(bss->drv->nl80211), 0, 0,
- cmd, 0);
+ nl80211_cmd(bss->drv, msg, 0, cmd);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
if (pmkid)
@@ -6727,6 +8586,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
nla_put_failure:
+ nlmsg_free(msg);
return -ENOBUFS;
}
@@ -6756,6 +8616,366 @@ static int nl80211_flush_pmkid(void *priv)
}
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+ const u8 *replay_ctr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nlattr *replay_nested;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+ replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
+ if (!replay_nested)
+ goto nla_put_failure;
+
+ NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
+ NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
+ NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
+ replay_ctr);
+
+ nla_nest_end(msg, replay_nested);
+
+ send_and_recv_msgs(drv, msg, NULL, NULL);
+ return;
+ nla_put_failure:
+ nlmsg_free(msg);
+}
+
+
+static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
+ const u8 *addr, int qos)
+{
+ /* send data frame to poll STA and check whether
+ * this frame is ACKed */
+ struct {
+ struct ieee80211_hdr hdr;
+ u16 qos_ctl;
+ } STRUCT_PACKED nulldata;
+ size_t size;
+
+ /* Send data frame to poll STA and check whether this frame is ACKed */
+
+ os_memset(&nulldata, 0, sizeof(nulldata));
+
+ if (qos) {
+ nulldata.hdr.frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA,
+ WLAN_FC_STYPE_QOS_NULL);
+ size = sizeof(nulldata);
+ } else {
+ nulldata.hdr.frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA,
+ WLAN_FC_STYPE_NULLFUNC);
+ size = sizeof(struct ieee80211_hdr);
+ }
+
+ nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
+ os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+ os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+ os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+ if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
+ wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
+ "send poll frame");
+}
+
+static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
+ int qos)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ if (!drv->poll_command_supported) {
+ nl80211_send_null_frame(bss, own_addr, addr, qos);
+ return;
+ }
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ send_and_recv_msgs(drv, msg, NULL, NULL);
+ return;
+ nla_put_failure:
+ nlmsg_free(msg);
+}
+
+
+static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
+ enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+
+static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
+ int ctwindow)
+{
+ struct i802_bss *bss = priv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
+ "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
+
+ if (opp_ps != -1 || ctwindow != -1)
+ return -1; /* Not yet supported */
+
+ if (legacy_ps == -1)
+ return 0;
+ if (legacy_ps != 0 && legacy_ps != 1)
+ return -1; /* Not yet supported */
+
+ return nl80211_set_power_save(bss, legacy_ps);
+}
+
+
+#ifdef CONFIG_TDLS
+
+static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
+ u8 dialog_token, u16 status_code,
+ const u8 *buf, size_t len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+ return -EOPNOTSUPP;
+
+ if (!dst)
+ return -EINVAL;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
+ NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
+ NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
+ NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
+ NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+
+static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ enum nl80211_tdls_operation nl80211_oper;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+ return -EOPNOTSUPP;
+
+ switch (oper) {
+ case TDLS_DISCOVERY_REQ:
+ nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
+ break;
+ case TDLS_SETUP:
+ nl80211_oper = NL80211_TDLS_SETUP;
+ break;
+ case TDLS_TEARDOWN:
+ nl80211_oper = NL80211_TDLS_TEARDOWN;
+ break;
+ case TDLS_ENABLE_LINK:
+ nl80211_oper = NL80211_TDLS_ENABLE_LINK;
+ break;
+ case TDLS_DISABLE_LINK:
+ nl80211_oper = NL80211_TDLS_DISABLE_LINK;
+ break;
+ case TDLS_ENABLE:
+ return 0;
+ case TDLS_DISABLE:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
+ NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+#endif /* CONFIG TDLS */
+
+
+#ifdef ANDROID
+
+typedef struct android_wifi_priv_cmd {
+ char *buf;
+ int used_len;
+ int total_len;
+} android_wifi_priv_cmd;
+
+static int drv_errors = 0;
+
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
+{
+ drv_errors++;
+ if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+ drv_errors = 0;
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+ }
+}
+
+
+static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ifreq ifr;
+ android_wifi_priv_cmd priv_cmd;
+ char buf[MAX_DRV_CMD_SIZE];
+ int ret;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_memset(&priv_cmd, 0, sizeof(priv_cmd));
+ os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+ os_memset(buf, 0, sizeof(buf));
+ os_strlcpy(buf, cmd, sizeof(buf));
+
+ priv_cmd.buf = buf;
+ priv_cmd.used_len = sizeof(buf);
+ priv_cmd.total_len = sizeof(buf);
+ ifr.ifr_data = &priv_cmd;
+
+ ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
+ __func__);
+ wpa_driver_send_hang_msg(drv);
+ return ret;
+ }
+
+ drv_errors = 0;
+ return 0;
+}
+
+
+static int android_pno_start(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ifreq ifr;
+ android_wifi_priv_cmd priv_cmd;
+ int ret = 0, i = 0, bp;
+ char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+ bp = WEXT_PNOSETUP_HEADER_SIZE;
+ os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+ buf[bp++] = WEXT_PNO_TLV_PREFIX;
+ buf[bp++] = WEXT_PNO_TLV_VERSION;
+ buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+ buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+ while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+ /* Check that there is enough space needed for 1 more SSID, the
+ * other sections and null termination */
+ if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
+ WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+ break;
+ wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+ params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ buf[bp++] = WEXT_PNO_SSID_SECTION;
+ buf[bp++] = params->ssids[i].ssid_len;
+ os_memcpy(&buf[bp], params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ bp += params->ssids[i].ssid_len;
+ i++;
+ }
+
+ buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+ WEXT_PNO_SCAN_INTERVAL);
+ bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+ buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+ WEXT_PNO_REPEAT);
+ bp += WEXT_PNO_REPEAT_LENGTH;
+
+ buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+ WEXT_PNO_MAX_REPEAT);
+ bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ memset(&priv_cmd, 0, sizeof(priv_cmd));
+ os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+ priv_cmd.buf = buf;
+ priv_cmd.used_len = bp;
+ priv_cmd.total_len = bp;
+ ifr.ifr_data = &priv_cmd;
+
+ ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+ ret);
+ wpa_driver_send_hang_msg(drv);
+ return ret;
+ }
+
+ drv_errors = 0;
+
+ return android_priv_cmd(bss, "PNOFORCE 1");
+}
+
+
+static int android_pno_stop(struct i802_bss *bss)
+{
+ return android_priv_cmd(bss, "PNOFORCE 0");
+}
+
+#endif /* ANDROID */
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -6763,6 +8983,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.get_ssid = wpa_driver_nl80211_get_ssid,
.set_key = wpa_driver_nl80211_set_key,
.scan2 = wpa_driver_nl80211_scan,
+ .sched_scan = wpa_driver_nl80211_sched_scan,
+ .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
.deauthenticate = wpa_driver_nl80211_deauthenticate,
.disassociate = wpa_driver_nl80211_disassociate,
@@ -6776,7 +8998,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.set_operstate = wpa_driver_nl80211_set_operstate,
.set_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country,
- .set_beacon = wpa_driver_nl80211_set_beacon,
+ .set_ap = wpa_driver_nl80211_set_ap,
.if_add = wpa_driver_nl80211_if_add,
.if_remove = wpa_driver_nl80211_if_remove,
.send_mlme = wpa_driver_nl80211_send_mlme,
@@ -6798,13 +9020,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.sta_clear_stats = i802_sta_clear_stats,
.set_rts = i802_set_rts,
.set_frag = i802_set_frag,
- .set_cts_protect = i802_set_cts_protect,
- .set_preamble = i802_set_preamble,
- .set_short_slot_time = i802_set_short_slot_time,
.set_tx_queue_params = i802_set_tx_queue_params,
.set_sta_vlan = i802_set_sta_vlan,
- .set_ht_params = i802_set_ht_params,
- .set_rate_sets = i802_set_rate_sets,
.sta_deauth = i802_sta_deauth,
.sta_disassoc = i802_sta_disassoc,
#endif /* HOSTAPD || CONFIG_AP */
@@ -6815,22 +9032,30 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.cancel_remain_on_channel =
wpa_driver_nl80211_cancel_remain_on_channel,
.probe_req_report = wpa_driver_nl80211_probe_req_report,
- .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
.deinit_ap = wpa_driver_nl80211_deinit_ap,
.resume = wpa_driver_nl80211_resume,
.send_ft_action = nl80211_send_ft_action,
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
.send_frame = nl80211_send_frame,
- .set_intra_bss = nl80211_set_intra_bss,
+ .shared_freq = wpa_driver_nl80211_shared_freq,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
.add_pmkid = nl80211_add_pmkid,
.remove_pmkid = nl80211_remove_pmkid,
.flush_pmkid = nl80211_flush_pmkid,
-#ifdef ANDROID_BRCM_P2P_PATCH
- .get_noa = wpa_driver_get_p2p_noa,
+ .set_rekey_info = nl80211_set_rekey_info,
+ .poll_client = nl80211_poll_client,
+#ifndef ANDROID_P2P
+ .set_p2p_powersave = nl80211_set_p2p_powersave,
+#endif
+#ifdef CONFIG_TDLS
+ .send_tdls_mgmt = nl80211_send_tdls_mgmt,
+ .tdls_oper = nl80211_tdls_oper,
+#endif /* CONFIG_TDLS */
+#ifdef ANDROID_P2P
.set_noa = wpa_driver_set_p2p_noa,
+ .get_noa = wpa_driver_get_p2p_noa,
.set_p2p_powersave = wpa_driver_set_p2p_ps,
.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
#endif
diff --git a/src/drivers/driver_osx.m b/src/drivers/driver_osx.m
deleted file mode 100644
index 69ca4b5..0000000
--- a/src/drivers/driver_osx.m
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * WPA Supplicant - Mac OS X Apple80211 driver interface
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#define Boolean __DummyBoolean
-#include <CoreFoundation/CoreFoundation.h>
-#undef Boolean
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-
-#include "Apple80211.h"
-
-struct wpa_driver_osx_data {
- void *ctx;
- WirelessRef wireless_ctx;
- CFArrayRef scan_results;
-};
-
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-extern int wpa_debug_level;
-
-static void dump_dict_cb(const void *key, const void *value, void *context)
-{
- if (MSG_DEBUG < wpa_debug_level)
- return;
-
- wpa_printf(MSG_DEBUG, "Key:");
- CFShow(key);
- wpa_printf(MSG_DEBUG, "Value:");
- CFShow(value);
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-
-static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
- wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
- title, (unsigned int) CFDictionaryGetCount(dict));
- CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
-static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
-{
- struct wpa_driver_osx_data *drv = priv;
- WirelessError err;
- WirelessInfo info;
- int len;
-
- err = WirelessGetInfo(drv->wireless_ctx, &info);
- if (err) {
- wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
- (int) err);
- return -1;
- }
- if (!info.power) {
- wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
- return -1;
- }
-
- for (len = 0; len < 32; len++)
- if (info.ssid[len] == 0)
- break;
-
- os_memcpy(ssid, info.ssid, len);
- return len;
-}
-
-
-static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
-{
- struct wpa_driver_osx_data *drv = priv;
- WirelessError err;
- WirelessInfo info;
-
- err = WirelessGetInfo(drv->wireless_ctx, &info);
- if (err) {
- wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
- (int) err);
- return -1;
- }
- if (!info.power) {
- wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
- return -1;
- }
-
- os_memcpy(bssid, info.bssID, ETH_ALEN);
- return 0;
-}
-
-
-static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static int wpa_driver_osx_scan(void *priv, struct wpa_driver_scan_params *params)
-{
- struct wpa_driver_osx_data *drv = priv;
- WirelessError err;
- const u8 *ssid = params->ssids[0].ssid;
- size_t ssid_len = params->ssids[0].ssid_len;
-
- if (drv->scan_results) {
- CFRelease(drv->scan_results);
- drv->scan_results = NULL;
- }
-
- if (ssid) {
- CFStringRef data;
- data = CFStringCreateWithBytes(kCFAllocatorDefault,
- ssid, ssid_len,
- kCFStringEncodingISOLatin1,
- FALSE);
- if (data == NULL) {
- wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
- "failed");
- return -1;
- }
-
- err = WirelessDirectedScan(drv->wireless_ctx,
- &drv->scan_results, 0, data);
- CFRelease(data);
- if (err) {
- wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
- "failed: 0x%08x", (unsigned int) err);
- return -1;
- }
- } else {
- err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
- if (err) {
- wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
- "0x%08x", (unsigned int) err);
- return -1;
- }
- }
-
- eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
- drv->ctx);
- return 0;
-}
-
-
-static void wpa_driver_osx_add_scan_entry(struct wpa_scan_results *res,
- WirelessNetworkInfo *info)
-{
- struct wpa_scan_res *result, **tmp;
- size_t extra_len;
- u8 *pos;
-
- extra_len = 2 + info->ssid_len;
-
- result = os_zalloc(sizeof(*result) + extra_len);
- if (result == NULL)
- return;
- os_memcpy(result->bssid, info->bssid, ETH_ALEN);
- result->freq = 2407 + info->channel * 5;
- //result->beacon_int =;
- result->caps = info->capability;
- //result->qual = info->signal;
- result->noise = info->noise;
-
- pos = (u8 *)(result + 1);
-
- *pos++ = WLAN_EID_SSID;
- *pos++ = info->ssid_len;
- os_memcpy(pos, info->ssid, info->ssid_len);
- pos += info->ssid_len;
-
- result->ie_len = pos - (u8 *)(result + 1);
-
- tmp = os_realloc(res->res,
- (res->num + 1) * sizeof(struct wpa_scan_res *));
- if (tmp == NULL) {
- os_free(result);
- return;
- }
- tmp[res->num++] = result;
- res->res = tmp;
-}
-
-
-static struct wpa_scan_results * wpa_driver_osx_get_scan_results(void *priv)
-{
- struct wpa_driver_osx_data *drv = priv;
- struct wpa_scan_results *res;
- size_t i, num;
-
- if (drv->scan_results == NULL)
- return 0;
-
- num = CFArrayGetCount(drv->scan_results);
-
- res = os_zalloc(sizeof(*res));
- if (res == NULL)
- return NULL;
-
- for (i = 0; i < num; i++)
- wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *)
- CFDataGetBytePtr(CFArrayGetValueAtIndex(
- drv->scan_results, i)));
-
- return res;
-}
-
-
-static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_driver_osx_data *drv = eloop_ctx;
- u8 bssid[ETH_ALEN];
- CFDictionaryRef ai;
-
- if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
- eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
- drv, drv->ctx);
- return;
- }
-
- ai = WirelessGetAssociationInfo(drv->wireless_ctx);
- if (ai) {
- wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
- CFRelease(ai);
- } else {
- wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
- }
-
- wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
-}
-
-
-static int wpa_driver_osx_associate(void *priv,
- struct wpa_driver_associate_params *params)
-{
- struct wpa_driver_osx_data *drv = priv;
- WirelessError err;
- CFDataRef ssid;
- CFStringRef key;
- int assoc_type;
-
- ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
- params->ssid_len);
- if (ssid == NULL)
- return -1;
-
- /* TODO: support for WEP */
- if (params->key_mgmt_suite == KEY_MGMT_PSK) {
- if (params->passphrase == NULL)
- return -1;
- key = CFStringCreateWithCString(kCFAllocatorDefault,
- params->passphrase,
- kCFStringEncodingISOLatin1);
- if (key == NULL) {
- CFRelease(ssid);
- return -1;
- }
- } else
- key = NULL;
-
- if (params->key_mgmt_suite == KEY_MGMT_NONE)
- assoc_type = 0;
- else
- assoc_type = 4;
-
- wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
- assoc_type, key);
- err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
- CFRelease(ssid);
- if (key)
- CFRelease(key);
- if (err) {
- wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
- (unsigned int) err);
- return -1;
- }
-
- /*
- * Driver is actually already associated; report association from an
- * eloop callback.
- */
- eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
- eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
- drv->ctx);
-
- return 0;
-}
-
-
-static int wpa_driver_osx_set_key(const char *ifname, void *priv,
- enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx, const u8 *seq,
- size_t seq_len, const u8 *key,
- size_t key_len)
-{
- struct wpa_driver_osx_data *drv = priv;
- WirelessError err;
-
- if (alg == WPA_ALG_WEP) {
- err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
- key);
- if (err != 0) {
- wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
- "0x%08x", (unsigned int) err);
- return -1;
- }
-
- return 0;
- }
-
- if (alg == WPA_ALG_PMK) {
- err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
- if (err != 0) {
- wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
- "0x%08x", (unsigned int) err);
- return -1;
- }
- return 0;
- }
-
- wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
- return -1;
-}
-
-
-static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
- os_memset(capa, 0, sizeof(*capa));
-
- capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
- capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
- WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
- capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
- WPA_DRIVER_AUTH_LEAP;
- capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
-
- return 0;
-}
-
-
-static void * wpa_driver_osx_init(void *ctx, const char *ifname)
-{
- struct wpa_driver_osx_data *drv;
- WirelessError err;
- u8 enabled, power;
-
- if (!WirelessIsAvailable()) {
- wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
- return NULL;
- }
-
- drv = os_zalloc(sizeof(*drv));
- if (drv == NULL)
- return NULL;
- drv->ctx = ctx;
- err = WirelessAttach(&drv->wireless_ctx, 0);
- if (err) {
- wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
- (int) err);
- os_free(drv);
- return NULL;
- }
-
- err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
- if (err)
- wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
- (unsigned int) err);
- err = WirelessGetPower(drv->wireless_ctx, &power);
- if (err)
- wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
- (unsigned int) err);
-
- wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
-
- if (!enabled) {
- err = WirelessSetEnabled(drv->wireless_ctx, 1);
- if (err) {
- wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
- " 0x%08x", (unsigned int) err);
- WirelessDetach(drv->wireless_ctx);
- os_free(drv);
- return NULL;
- }
- }
-
- if (!power) {
- err = WirelessSetPower(drv->wireless_ctx, 1);
- if (err) {
- wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
- "0x%08x", (unsigned int) err);
- WirelessDetach(drv->wireless_ctx);
- os_free(drv);
- return NULL;
- }
- }
-
- return drv;
-}
-
-
-static void wpa_driver_osx_deinit(void *priv)
-{
- struct wpa_driver_osx_data *drv = priv;
- WirelessError err;
-
- eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
- eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
-
- err = WirelessSetPower(drv->wireless_ctx, 0);
- if (err) {
- wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
- "0x%08x", (unsigned int) err);
- }
-
- err = WirelessDetach(drv->wireless_ctx);
- if (err) {
- wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
- (unsigned int) err);
- }
-
- if (drv->scan_results)
- CFRelease(drv->scan_results);
-
- os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_osx_ops = {
- .name = "osx",
- .desc = "Mac OS X Apple80211 driver",
- .get_ssid = wpa_driver_osx_get_ssid,
- .get_bssid = wpa_driver_osx_get_bssid,
- .init = wpa_driver_osx_init,
- .deinit = wpa_driver_osx_deinit,
- .scan2 = wpa_driver_osx_scan,
- .get_scan_results2 = wpa_driver_osx_get_scan_results,
- .associate = wpa_driver_osx_associate,
- .set_key = wpa_driver_osx_set_key,
- .get_capa = wpa_driver_osx_get_capa,
-};
diff --git a/src/drivers/driver_ralink.c b/src/drivers/driver_ralink.c
deleted file mode 100644
index a1e27be..0000000
--- a/src/drivers/driver_ralink.c
+++ /dev/null
@@ -1,1498 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with Ralink Wireless Client
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "l2_packet/l2_packet.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "priv_netlink.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-#include "driver_ralink.h"
-
-static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx);
-
-#define MAX_SSID_LEN 32
-
-struct wpa_driver_ralink_data {
- void *ctx;
- int ioctl_sock;
- struct netlink_data *netlink;
- char ifname[IFNAMSIZ + 1];
- u8 *assoc_req_ies;
- size_t assoc_req_ies_len;
- u8 *assoc_resp_ies;
- size_t assoc_resp_ies_len;
- int no_of_pmkid;
- struct ndis_pmkid_entry *pmkid;
- int we_version_compiled;
- int ap_scan;
- int scanning_done;
- u8 g_driver_down;
- BOOLEAN bAddWepKey;
-};
-
-static int ralink_set_oid(struct wpa_driver_ralink_data *drv,
- unsigned short oid, char *data, int len)
-{
- char *buf;
- struct iwreq iwr;
-
- buf = os_zalloc(len);
- if (buf == NULL)
- return -1;
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.data.flags = oid;
- iwr.u.data.flags |= OID_GET_SET_TOGGLE;
-
- if (data)
- os_memcpy(buf, data, len);
-
- iwr.u.data.pointer = (caddr_t) buf;
- iwr.u.data.length = len;
-
- if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
- wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
- __func__, oid, len);
- os_free(buf);
- return -1;
- }
- os_free(buf);
- return 0;
-}
-
-static int
-ralink_get_new_driver_flag(struct wpa_driver_ralink_data *drv)
-{
- struct iwreq iwr;
- UCHAR enabled = 0;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.data.pointer = (UCHAR*) &enabled;
- iwr.u.data.flags = RT_OID_NEW_DRIVER;
-
- if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
- wpa_printf(MSG_DEBUG, "%s: failed", __func__);
- return 0;
- }
-
- return (enabled == 1) ? 1 : 0;
-}
-
-static int wpa_driver_ralink_get_bssid(void *priv, u8 *bssid)
-{
- struct wpa_driver_ralink_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
-
- if (drv->g_driver_down == 1)
- return -1;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
- if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
- perror("ioctl[SIOCGIWAP]");
- ret = -1;
- }
- os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
-
- return ret;
-}
-
-static int wpa_driver_ralink_get_ssid(void *priv, u8 *ssid)
-{
- struct wpa_driver_ralink_data *drv = priv;
-#if 0
- struct wpa_supplicant *wpa_s = drv->ctx;
- struct wpa_ssid *entry;
-#endif
- int ssid_len;
- u8 bssid[ETH_ALEN];
- u8 ssid_str[MAX_SSID_LEN];
- struct iwreq iwr;
-#if 0
- int result = 0;
-#endif
- int ret = 0;
-#if 0
- BOOLEAN ieee8021x_mode = FALSE;
- BOOLEAN ieee8021x_required_key = FALSE;
-#endif
-
- if (drv->g_driver_down == 1)
- return -1;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.essid.pointer = (caddr_t) ssid;
- iwr.u.essid.length = 32;
-
- if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCGIWESSID]");
- ret = -1;
- } else
- ret = iwr.u.essid.length;
-
- if (ret <= 0)
- return ret;
-
- ssid_len = ret;
- os_memset(ssid_str, 0, MAX_SSID_LEN);
- os_memcpy(ssid_str, ssid, ssid_len);
-
- if (drv->ap_scan == 0) {
- /* Read BSSID form driver */
- if (wpa_driver_ralink_get_bssid(priv, bssid) < 0) {
- wpa_printf(MSG_WARNING, "Could not read BSSID from "
- "driver.");
- return ret;
- }
-
-#if 0
- entry = wpa_s->conf->ssid;
- while (entry) {
- if (!entry->disabled && ssid_len == entry->ssid_len &&
- os_memcmp(ssid_str, entry->ssid, ssid_len) == 0 &&
- (!entry->bssid_set ||
- os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) {
- /* match the config of driver */
- result = 1;
- break;
- }
- entry = entry->next;
- }
-
- if (result) {
- wpa_printf(MSG_DEBUG, "Ready to set 802.1x mode and "
- "ieee_required_keys parameters to driver");
-
- /* set 802.1x mode and ieee_required_keys parameter */
- if (entry->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
- if ((entry->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST)))
- ieee8021x_required_key = TRUE;
- ieee8021x_mode = TRUE;
- }
-
- if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, (char *) &ieee8021x_mode, sizeof(BOOLEAN)) < 0)
- {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set OID_802_11_SET_IEEE8021X(%d)", (int) ieee8021x_mode);
- }
- else
- {
- wpa_printf(MSG_DEBUG, "ieee8021x_mode is %s", ieee8021x_mode ? "TRUE" : "FALSE");
- }
-
- if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
- {
- wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", (int) ieee8021x_required_key);
- }
- else
- {
- wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d)", ieee8021x_required_key ? "TRUE" : "FALSE",
- entry->eapol_flags);
- }
- }
-#endif
- }
-
- return ret;
-}
-
-static int wpa_driver_ralink_set_ssid(struct wpa_driver_ralink_data *drv,
- const u8 *ssid, size_t ssid_len)
-{
- NDIS_802_11_SSID *buf;
- int ret = 0;
- struct iwreq iwr;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- buf = os_zalloc(sizeof(NDIS_802_11_SSID));
- if (buf == NULL)
- return -1;
- os_memset(buf, 0, sizeof(buf));
- buf->SsidLength = ssid_len;
- os_memcpy(buf->Ssid, ssid, ssid_len);
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
- iwr.u.data.flags = OID_802_11_SSID;
- iwr.u.data.flags |= OID_GET_SET_TOGGLE;
- iwr.u.data.pointer = (caddr_t) buf;
- iwr.u.data.length = sizeof(NDIS_802_11_SSID);
-
- if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
- perror("ioctl[RT_PRIV_IOCTL] -- OID_802_11_SSID");
- ret = -1;
- }
- os_free(buf);
- return ret;
-}
-
-static void wpa_driver_ralink_event_pmkid(struct wpa_driver_ralink_data *drv,
- const u8 *data, size_t data_len)
-{
- NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
- size_t i;
- union wpa_event_data event;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- if (data_len < 8) {
- wpa_printf(MSG_DEBUG, "RALINK: Too short PMKID Candidate List "
- "Event (len=%lu)", (unsigned long) data_len);
- return;
- }
- pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
- wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List Event - Version %d"
- " NumCandidates %d",
- (int) pmkid->Version, (int) pmkid->NumCandidates);
-
- if (pmkid->Version != 1) {
- wpa_printf(MSG_DEBUG, "RALINK: Unsupported PMKID Candidate "
- "List Version %d", (int) pmkid->Version);
- return;
- }
-
- if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
- wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List "
- "underflow");
-
- return;
- }
-
-
-
- os_memset(&event, 0, sizeof(event));
- for (i = 0; i < pmkid->NumCandidates; i++) {
- PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
- wpa_printf(MSG_DEBUG, "RALINK: %lu: " MACSTR " Flags 0x%x",
- (unsigned long) i, MAC2STR(p->BSSID),
- (int) p->Flags);
- os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
- event.pmkid_candidate.index = i;
- event.pmkid_candidate.preauth =
- p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
- wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
- &event);
- }
-}
-
-static int wpa_driver_ralink_set_pmkid(struct wpa_driver_ralink_data *drv)
-{
- int len, count, i, ret;
- struct ndis_pmkid_entry *entry;
- NDIS_802_11_PMKID *p;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- count = 0;
- entry = drv->pmkid;
- while (entry) {
- count++;
- if (count >= drv->no_of_pmkid)
- break;
- entry = entry->next;
- }
- len = 8 + count * sizeof(BSSID_INFO);
- p = os_zalloc(len);
- if (p == NULL)
- return -1;
- p->Length = len;
- p->BSSIDInfoCount = count;
- entry = drv->pmkid;
- for (i = 0; i < count; i++) {
- os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
- os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
- entry = entry->next;
- }
- wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID",
- (const u8 *) p, len);
- ret = ralink_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
- os_free(p);
- return ret;
-}
-
-static int wpa_driver_ralink_add_pmkid(void *priv, const u8 *bssid,
- const u8 *pmkid)
-{
- struct wpa_driver_ralink_data *drv = priv;
- struct ndis_pmkid_entry *entry, *prev;
-
- if (drv->g_driver_down == 1)
- return -1;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- if (drv->no_of_pmkid == 0)
- return 0;
-
- prev = NULL;
- entry = drv->pmkid;
- while (entry) {
- if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
- break;
- prev = entry;
- entry = entry->next;
- }
-
- if (entry) {
- /* Replace existing entry for this BSSID and move it into the
- * beginning of the list. */
- os_memcpy(entry->pmkid, pmkid, 16);
- if (prev) {
- prev->next = entry->next;
- entry->next = drv->pmkid;
- drv->pmkid = entry;
- }
- } else {
- entry = os_malloc(sizeof(*entry));
- if (entry) {
- os_memcpy(entry->bssid, bssid, ETH_ALEN);
- os_memcpy(entry->pmkid, pmkid, 16);
- entry->next = drv->pmkid;
- drv->pmkid = entry;
- }
- }
-
- return wpa_driver_ralink_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ralink_remove_pmkid(void *priv, const u8 *bssid,
- const u8 *pmkid)
-{
- struct wpa_driver_ralink_data *drv = priv;
- struct ndis_pmkid_entry *entry, *prev;
-
- if (drv->g_driver_down == 1)
- return -1;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- if (drv->no_of_pmkid == 0)
- return 0;
-
- entry = drv->pmkid;
- prev = NULL;
- drv->pmkid = NULL;
- while (entry) {
- if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
- os_memcmp(entry->pmkid, pmkid, 16) == 0) {
- if (prev)
- prev->next = entry->next;
- else
- drv->pmkid = entry->next;
- os_free(entry);
- break;
- }
- prev = entry;
- entry = entry->next;
- }
- return wpa_driver_ralink_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ralink_flush_pmkid(void *priv)
-{
- struct wpa_driver_ralink_data *drv = priv;
- NDIS_802_11_PMKID p;
- struct ndis_pmkid_entry *pmkid, *prev;
-
- if (drv->g_driver_down == 1)
- return -1;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- if (drv->no_of_pmkid == 0)
- return 0;
-
- pmkid = drv->pmkid;
- drv->pmkid = NULL;
- while (pmkid) {
- prev = pmkid;
- pmkid = pmkid->next;
- os_free(prev);
- }
-
- os_memset(&p, 0, sizeof(p));
- p.Length = 8;
- p.BSSIDInfoCount = 0;
- wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
- (const u8 *) &p, 8);
- return ralink_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
-}
-
-static void
-wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
- void *ctx, char *custom)
-{
- union wpa_event_data data;
- u8 *req_ies = NULL, *resp_ies = NULL;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
-
- os_memset(&data, 0, sizeof(data));
- /* Host AP driver */
- if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
- /* receive a MICFAILURE report */
- data.michael_mic_failure.unicast =
- os_strstr(custom, " unicast") != NULL;
- /* TODO: parse parameters(?) */
- wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
- } else if (os_strncmp(custom, "ASSOCINFO_ReqIEs=", 17) == 0) {
- /* receive assoc. req. IEs */
- char *spos;
- int bytes;
-
- spos = custom + 17;
- /*get IE's length */
- /*
- * bytes = strlen(spos); ==> bug, bytes may less than original
- * size by using this way to get size. snowpin 20070312
- * if (!bytes)
- * return;
- */
- bytes = drv->assoc_req_ies_len;
-
- req_ies = os_malloc(bytes);
- if (req_ies == NULL)
- return;
- os_memcpy(req_ies, spos, bytes);
- data.assoc_info.req_ies = req_ies;
- data.assoc_info.req_ies_len = bytes;
-
- /* skip the '\0' byte */
- spos += bytes + 1;
-
- data.assoc_info.resp_ies = NULL;
- data.assoc_info.resp_ies_len = 0;
-
- if (os_strncmp(spos, " RespIEs=", 9) == 0) {
- /* receive assoc. resp. IEs */
- spos += 9;
- /* get IE's length */
- bytes = os_strlen(spos);
- if (!bytes)
- goto done;
-
- resp_ies = os_malloc(bytes);
- if (resp_ies == NULL)
- goto done;
- os_memcpy(resp_ies, spos, bytes);
- data.assoc_info.resp_ies = resp_ies;
- data.assoc_info.resp_ies_len = bytes;
- }
-
- wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
-
- done:
- /* free allocated memory */
- os_free(resp_ies);
- os_free(req_ies);
- }
-}
-
-static void ralink_interface_up(struct wpa_driver_ralink_data *drv)
-{
- union wpa_event_data event;
- int enable_wpa_supplicant = 0;
- drv->g_driver_down = 0;
- os_memset(&event, 0, sizeof(event));
- os_snprintf(event.interface_status.ifname,
- sizeof(event.interface_status.ifname), "%s", drv->ifname);
-
- event.interface_status.ievent = EVENT_INTERFACE_ADDED;
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
-
- if (drv->ap_scan == 1)
- enable_wpa_supplicant = 1;
- else
- enable_wpa_supplicant = 2;
- /* trigger driver support wpa_supplicant */
- if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
- (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
- {
- wpa_printf(MSG_INFO, "RALINK: Failed to set "
- "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
- (int) enable_wpa_supplicant);
- wpa_printf(MSG_ERROR, "ralink. Driver does not support "
- "wpa_supplicant");
- }
-}
-
-static void
-wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
- void *ctx, char *data, int len)
-{
- struct iw_event iwe_buf, *iwe = &iwe_buf;
- char *pos, *end, *custom, *buf, *assoc_info_buf, *info_pos;
-#if 0
- BOOLEAN ieee8021x_required_key = FALSE;
-#endif
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- assoc_info_buf = info_pos = NULL;
- pos = data;
- end = data + len;
-
- while (pos + IW_EV_LCP_LEN <= end) {
- /* Event data may be unaligned, so make a local, aligned copy
- * before processing. */
- os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
- wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
- iwe->cmd, iwe->len);
- if (iwe->len <= IW_EV_LCP_LEN)
- return;
-
- custom = pos + IW_EV_POINT_LEN;
-
- if (drv->we_version_compiled > 18 && iwe->cmd == IWEVCUSTOM) {
- /* WE-19 removed the pointer from struct iw_point */
- char *dpos = (char *) &iwe_buf.u.data.length;
- int dlen = dpos - (char *) &iwe_buf;
- os_memcpy(dpos, pos + IW_EV_LCP_LEN,
- sizeof(struct iw_event) - dlen);
- } else {
- os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
- custom += IW_EV_POINT_OFF;
- }
-
- switch (iwe->cmd) {
- case IWEVCUSTOM:
- if (custom + iwe->u.data.length > end)
- return;
- buf = os_malloc(iwe->u.data.length + 1);
- if (buf == NULL)
- return;
- os_memcpy(buf, custom, iwe->u.data.length);
- buf[iwe->u.data.length] = '\0';
-
- if (drv->ap_scan == 1) {
- if ((iwe->u.data.flags == RT_ASSOC_EVENT_FLAG)
- || (iwe->u.data.flags ==
- RT_REQIE_EVENT_FLAG) ||
- (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG)
- || (iwe->u.data.flags ==
- RT_ASSOCINFO_EVENT_FLAG)) {
- if (drv->scanning_done == 0) {
- os_free(buf);
- return;
- }
- }
- }
-
- if (iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) {
- wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
- wpa_printf(MSG_DEBUG, "Custom wireless event: "
- "receive ASSOCIATED_EVENT !!!");
- } else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) {
- wpa_printf(MSG_DEBUG, "Custom wireless event: "
- "receive ReqIEs !!!");
- drv->assoc_req_ies =
- os_malloc(iwe->u.data.length);
- if (drv->assoc_req_ies == NULL) {
- os_free(buf);
- return;
- }
-
- drv->assoc_req_ies_len = iwe->u.data.length;
- os_memcpy(drv->assoc_req_ies, custom,
- iwe->u.data.length);
- } else if (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG) {
- wpa_printf(MSG_DEBUG, "Custom wireless event: "
- "receive RespIEs !!!");
- drv->assoc_resp_ies =
- os_malloc(iwe->u.data.length);
- if (drv->assoc_resp_ies == NULL) {
- os_free(drv->assoc_req_ies);
- drv->assoc_req_ies = NULL;
- os_free(buf);
- return;
- }
-
- drv->assoc_resp_ies_len = iwe->u.data.length;
- os_memcpy(drv->assoc_resp_ies, custom,
- iwe->u.data.length);
- } else if (iwe->u.data.flags ==
- RT_ASSOCINFO_EVENT_FLAG) {
- wpa_printf(MSG_DEBUG, "Custom wireless event: "
- "receive ASSOCINFO_EVENT !!!");
-
- assoc_info_buf =
- os_zalloc(drv->assoc_req_ies_len +
- drv->assoc_resp_ies_len + 1);
-
- if (assoc_info_buf == NULL) {
- os_free(drv->assoc_req_ies);
- drv->assoc_req_ies = NULL;
- os_free(drv->assoc_resp_ies);
- drv->assoc_resp_ies = NULL;
- os_free(buf);
- return;
- }
-
- if (drv->assoc_req_ies) {
- os_memcpy(assoc_info_buf,
- drv->assoc_req_ies,
- drv->assoc_req_ies_len);
- }
- info_pos = assoc_info_buf +
- drv->assoc_req_ies_len;
- if (drv->assoc_resp_ies) {
- os_memcpy(info_pos,
- drv->assoc_resp_ies,
- drv->assoc_resp_ies_len);
- }
- assoc_info_buf[drv->assoc_req_ies_len +
- drv->assoc_resp_ies_len] = '\0';
- wpa_driver_ralink_event_wireless_custom(
- drv, ctx, assoc_info_buf);
- os_free(drv->assoc_req_ies);
- drv->assoc_req_ies = NULL;
- os_free(drv->assoc_resp_ies);
- drv->assoc_resp_ies = NULL;
- os_free(assoc_info_buf);
- } else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG)
- {
- wpa_printf(MSG_DEBUG, "Custom wireless event: "
- "receive DISASSOCIATED_EVENT !!!");
- wpa_supplicant_event(ctx, EVENT_DISASSOC,
- NULL);
- } else if (iwe->u.data.flags == RT_PMKIDCAND_FLAG) {
- wpa_printf(MSG_DEBUG, "Custom wireless event: "
- "receive PMKIDCAND_EVENT !!!");
- wpa_driver_ralink_event_pmkid(
- drv, (const u8 *) custom,
- iwe->u.data.length);
- } else if (iwe->u.data.flags == RT_INTERFACE_DOWN) {
- drv->g_driver_down = 1;
- eloop_terminate();
- } else if (iwe->u.data.flags == RT_INTERFACE_UP) {
- ralink_interface_up(drv);
- } else {
- wpa_driver_ralink_event_wireless_custom(
- drv, ctx, buf);
- }
- os_free(buf);
- break;
- }
-
- pos += iwe->len;
- }
-}
-
-static void
-wpa_driver_ralink_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
- u8 *buf, size_t len)
-{
- struct wpa_driver_ralink_data *drv = ctx;
- int attrlen, rta_len;
- struct rtattr *attr;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg));
-
- attrlen = len;
- wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen);
- attr = (struct rtattr *) buf;
- wpa_hexdump(MSG_DEBUG, "attr1: ", (u8 *) attr, sizeof(struct rtattr));
- rta_len = RTA_ALIGN(sizeof(struct rtattr));
- wpa_hexdump(MSG_DEBUG, "attr2: ", (u8 *)attr,rta_len);
- while (RTA_OK(attr, attrlen)) {
- wpa_printf(MSG_DEBUG, "rta_type=%02x\n", attr->rta_type);
- if (attr->rta_type == IFLA_WIRELESS) {
- wpa_driver_ralink_event_wireless(
- drv, ctx,
- ((char *) attr) + rta_len,
- attr->rta_len - rta_len);
- }
- attr = RTA_NEXT(attr, attrlen);
- wpa_hexdump(MSG_DEBUG, "attr3: ",
- (u8 *) attr, sizeof(struct rtattr));
- }
-}
-
-static int
-ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
-{
- struct iwreq iwr;
- UINT we_version_compiled = 0;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.data.pointer = (caddr_t) &we_version_compiled;
- iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED;
-
- if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
- wpa_printf(MSG_DEBUG, "%s: failed", __func__);
- return -1;
- }
-
- drv->we_version_compiled = we_version_compiled;
-
- return 0;
-}
-
-static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
-{
- int s;
- struct wpa_driver_ralink_data *drv;
- struct ifreq ifr;
- UCHAR enable_wpa_supplicant = 0;
- struct netlink_config *cfg;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- /* open socket to kernel */
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- perror("socket");
- return NULL;
- }
- /* do it */
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-
- if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
- perror(ifr.ifr_name);
- return NULL;
- }
-
- drv = os_zalloc(sizeof(*drv));
- if (drv == NULL)
- return NULL;
-
- drv->scanning_done = 1;
- drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */
- drv->ctx = ctx;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->ioctl_sock = s;
- drv->g_driver_down = 0;
-
- cfg = os_zalloc(sizeof(*cfg));
- if (cfg == NULL) {
- close(drv->ioctl_sock);
- os_free(drv);
- return NULL;
- }
- cfg->ctx = drv;
- cfg->newlink_cb = wpa_driver_ralink_event_rtm_newlink;
- drv->netlink = netlink_init(cfg);
- if (drv->netlink == NULL) {
- os_free(cfg);
- close(drv->ioctl_sock);
- os_free(drv);
- return NULL;
- }
-
- drv->no_of_pmkid = 4; /* Number of PMKID saved supported */
-
- linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
- ralink_get_we_version_compiled(drv);
- wpa_driver_ralink_flush_pmkid(drv);
-
- if (drv->ap_scan == 1)
- enable_wpa_supplicant = 1;
- else
- enable_wpa_supplicant = 2;
- /* trigger driver support wpa_supplicant */
- if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
- (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
- {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
- "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
- (int) enable_wpa_supplicant);
- wpa_printf(MSG_ERROR, "RALINK: Driver does not support "
- "wpa_supplicant");
- close(s);
- close(drv->ioctl_sock);
- os_free(drv);
- return NULL;
- }
-
- if (drv->ap_scan == 1)
- drv->scanning_done = 0;
-
- return drv;
-}
-
-static void wpa_driver_ralink_deinit(void *priv)
-{
- struct wpa_driver_ralink_data *drv = priv;
- UCHAR enable_wpa_supplicant;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- enable_wpa_supplicant = 0;
-
- if (drv->g_driver_down == 0) {
- /* trigger driver disable wpa_supplicant support */
- if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
- (char *) &enable_wpa_supplicant,
- sizeof(BOOLEAN)) < 0) {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
- "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
- (int) enable_wpa_supplicant);
- }
-
- wpa_driver_ralink_flush_pmkid(drv);
-
- sleep(1);
- /* linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); */
- }
-
- eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
- netlink_deinit(drv->netlink);
- close(drv->ioctl_sock);
- os_free(drv);
-}
-
-static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_driver_ralink_data *drv = eloop_ctx;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
- wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-
- drv->scanning_done = 1;
-
-}
-
-static int wpa_driver_ralink_scan(void *priv,
- struct wpa_driver_scan_params *params)
-{
- struct wpa_driver_ralink_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
-
- if (drv->g_driver_down == 1)
- return -1;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-#if 0
- if (ssid_len > IW_ESSID_MAX_SIZE) {
- wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
- __FUNCTION__, (unsigned long) ssid_len);
- return -1;
- }
-
- /* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */
-#endif
-
- if (ralink_set_oid(drv, RT_OID_WPS_PROBE_REQ_IE,
- (char *) params->extra_ies, params->extra_ies_len) <
- 0) {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
- "RT_OID_WPS_PROBE_REQ_IE");
- }
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
- if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
- perror("ioctl[SIOCSIWSCAN]");
- ret = -1;
- }
-
- /* Not all drivers generate "scan completed" wireless event, so try to
- * read results after a timeout. */
- eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
- eloop_register_timeout(4, 0, wpa_driver_ralink_scan_timeout, drv,
- drv->ctx);
-
- drv->scanning_done = 0;
-
- return ret;
-}
-
-static struct wpa_scan_results *
-wpa_driver_ralink_get_scan_results(void *priv)
-{
- struct wpa_driver_ralink_data *drv = priv;
- UCHAR *buf = NULL;
- size_t buf_len;
- NDIS_802_11_BSSID_LIST_EX *wsr;
- NDIS_WLAN_BSSID_EX *wbi;
- struct iwreq iwr;
- size_t ap_num;
- u8 *pos;
- struct wpa_scan_results *res;
-
- if (drv->g_driver_down == 1)
- return NULL;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- if (drv->we_version_compiled >= 17)
- buf_len = 8192;
- else
- buf_len = 4096;
-
- for (;;) {
- buf = os_zalloc(buf_len);
- iwr.u.data.length = buf_len;
- if (buf == NULL)
- return NULL;
-
- wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
-
- wsr->NumberOfItems = 0;
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.data.pointer = (void *) buf;
- iwr.u.data.flags = OID_802_11_BSSID_LIST;
-
- if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) == 0)
- break;
-
- if (errno == E2BIG && buf_len < 65535) {
- os_free(buf);
- buf = NULL;
- buf_len *= 2;
- if (buf_len > 65535)
- buf_len = 65535; /* 16-bit length field */
- wpa_printf(MSG_DEBUG, "Scan results did not fit - "
- "trying larger buffer (%lu bytes)",
- (unsigned long) buf_len);
- } else {
- perror("ioctl[RT_PRIV_IOCTL]");
- os_free(buf);
- return NULL;
- }
- }
-
- res = os_zalloc(sizeof(*res));
- if (res == NULL) {
- os_free(buf);
- return NULL;
- }
-
- res->res = os_zalloc(wsr->NumberOfItems *
- sizeof(struct wpa_scan_res *));
- if (res->res == NULL) {
- os_free(res);
- os_free(buf);
- return NULL;
- }
-
- for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems;
- ++ap_num) {
- struct wpa_scan_res *r = NULL;
- size_t extra_len = 0, var_ie_len = 0;
- u8 *pos2;
-
- /* SSID data element */
- extra_len += 2 + wbi->Ssid.SsidLength;
- var_ie_len = wbi->IELength - sizeof(NDIS_802_11_FIXED_IEs);
- r = os_zalloc(sizeof(*r) + extra_len + var_ie_len);
- if (r == NULL)
- break;
- res->res[res->num++] = r;
-
- wpa_printf(MSG_DEBUG, "SSID - %s", wbi->Ssid.Ssid);
- /* get ie's */
- wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs",
- (u8 *) &wbi->IEs[0], wbi->IELength);
-
- os_memcpy(r->bssid, wbi->MacAddress, ETH_ALEN);
-
- extra_len += (2 + wbi->Ssid.SsidLength);
- r->ie_len = extra_len + var_ie_len;
- pos2 = (u8 *) (r + 1);
-
- /*
- * Generate a fake SSID IE since the driver did not report
- * a full IE list.
- */
- *pos2++ = WLAN_EID_SSID;
- *pos2++ = wbi->Ssid.SsidLength;
- os_memcpy(pos2, wbi->Ssid.Ssid, wbi->Ssid.SsidLength);
- pos2 += wbi->Ssid.SsidLength;
-
- r->freq = (wbi->Configuration.DSConfig / 1000);
-
- pos = (u8 *) wbi + sizeof(*wbi) - 1;
-
- pos += sizeof(NDIS_802_11_FIXED_IEs) - 2;
- os_memcpy(&(r->caps), pos, 2);
- pos += 2;
-
- if (wbi->IELength > sizeof(NDIS_802_11_FIXED_IEs))
- os_memcpy(pos2, pos, var_ie_len);
-
- wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length);
- }
-
- os_free(buf);
- return res;
-}
-
-static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv,
- NDIS_802_11_AUTHENTICATION_MODE mode)
-{
- NDIS_802_11_AUTHENTICATION_MODE auth_mode = mode;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- if (ralink_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
- (char *) &auth_mode, sizeof(auth_mode)) < 0) {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
- "OID_802_11_AUTHENTICATION_MODE (%d)",
- (int) auth_mode);
- return -1;
- }
- return 0;
-}
-
-static int ralink_set_encr_type(struct wpa_driver_ralink_data *drv,
- NDIS_802_11_WEP_STATUS encr_type)
-{
- NDIS_802_11_WEP_STATUS wep_status = encr_type;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- if (ralink_set_oid(drv, OID_802_11_WEP_STATUS,
- (char *) &wep_status, sizeof(wep_status)) < 0) {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
- "OID_802_11_WEP_STATUS (%d)",
- (int) wep_status);
- return -1;
- }
- return 0;
-}
-
-
-static int wpa_driver_ralink_remove_key(struct wpa_driver_ralink_data *drv,
- int key_idx, const u8 *addr,
- const u8 *bssid, int pairwise)
-{
- NDIS_802_11_REMOVE_KEY rkey;
- NDIS_802_11_KEY_INDEX _index;
- int res, res2;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- os_memset(&rkey, 0, sizeof(rkey));
-
- rkey.Length = sizeof(rkey);
- rkey.KeyIndex = key_idx;
-
- if (pairwise)
- rkey.KeyIndex |= 1 << 30;
-
- os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
-
- res = ralink_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
- sizeof(rkey));
-
- /* AlbertY@20060210 removed it */
- if (0 /* !pairwise */) {
- res2 = ralink_set_oid(drv, OID_802_11_REMOVE_WEP,
- (char *) &_index, sizeof(_index));
- } else
- res2 = 0;
-
- if (res < 0 && res2 < 0)
- return res;
- return 0;
-}
-
-static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv,
- int pairwise, int key_idx, int set_tx,
- const u8 *key, size_t key_len)
-{
- NDIS_802_11_WEP *wep;
- size_t len;
- int res;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- len = 12 + key_len;
- wep = os_zalloc(len);
- if (wep == NULL)
- return -1;
-
- wep->Length = len;
- wep->KeyIndex = key_idx;
-
- if (set_tx)
- wep->KeyIndex |= 0x80000000;
-
- wep->KeyLength = key_len;
- os_memcpy(wep->KeyMaterial, key, key_len);
-
- wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_WEP",
- (const u8 *) wep, len);
- res = ralink_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
-
- os_free(wep);
-
- return res;
-}
-
-static int wpa_driver_ralink_set_key(const char *ifname, void *priv,
- enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
- struct wpa_driver_ralink_data *drv = priv;
- size_t len, i;
- NDIS_802_11_KEY *nkey;
- int res, pairwise;
- u8 bssid[ETH_ALEN];
-
- if (drv->g_driver_down == 1)
- return -1;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- drv->bAddWepKey = FALSE;
-
- if (addr == NULL || is_broadcast_ether_addr(addr)) {
- /* Group Key */
- pairwise = 0;
- wpa_driver_ralink_get_bssid(drv, bssid);
- } else {
- /* Pairwise Key */
- pairwise = 1;
- os_memcpy(bssid, addr, ETH_ALEN);
- }
-
- if (alg == WPA_ALG_NONE || key_len == 0) {
- return wpa_driver_ralink_remove_key(drv, key_idx, addr, bssid,
- pairwise);
- }
-
- if (alg == WPA_ALG_WEP) {
- drv->bAddWepKey = TRUE;
- return wpa_driver_ralink_add_wep(drv, pairwise, key_idx,
- set_tx, key, key_len);
- }
-
- len = 12 + 6 + 6 + 8 + key_len;
-
- nkey = os_zalloc(len);
- if (nkey == NULL)
- return -1;
-
- nkey->Length = len;
- nkey->KeyIndex = key_idx;
-
- if (set_tx)
- nkey->KeyIndex |= 1 << 31;
-
- if (pairwise)
- nkey->KeyIndex |= 1 << 30;
-
- if (seq && seq_len)
- nkey->KeyIndex |= 1 << 29;
-
- nkey->KeyLength = key_len;
- os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
-
- if (seq && seq_len) {
- for (i = 0; i < seq_len; i++)
- nkey->KeyRSC |= seq[i] << (i * 8);
- }
- if (alg == WPA_ALG_TKIP && key_len == 32) {
- os_memcpy(nkey->KeyMaterial, key, 16);
- os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
- os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
- } else {
- os_memcpy(nkey->KeyMaterial, key, key_len);
- }
-
- wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
- "key_len=%lu", __FUNCTION__, alg, key_idx, set_tx,
- (unsigned long) seq_len, (unsigned long) key_len);
-
- wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_KEY",
- (const u8 *) nkey, len);
- res = ralink_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
- os_free(nkey);
-
- return res;
-}
-
-static int wpa_driver_ralink_disassociate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct wpa_driver_ralink_data *drv = priv;
-
- if (drv->g_driver_down == 1)
- return -1;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- if (ralink_set_oid(drv, OID_802_11_DISASSOCIATE, " ", 4) < 0) {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
- "OID_802_11_DISASSOCIATE");
- }
-
- return 0;
-}
-
-static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct wpa_driver_ralink_data *drv = priv;
-
- wpa_printf(MSG_DEBUG, "g_driver_down = %d", drv->g_driver_down);
-
- if (drv->g_driver_down == 1)
- return -1;
-
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- if (ralink_get_new_driver_flag(drv) == 0) {
- return wpa_driver_ralink_disassociate(priv, addr, reason_code);
- } else {
- MLME_DEAUTH_REQ_STRUCT mlme;
- os_memset(&mlme, 0, sizeof(MLME_DEAUTH_REQ_STRUCT));
- mlme.Reason = reason_code;
- os_memcpy(mlme.Addr, addr, MAC_ADDR_LEN);
- return ralink_set_oid(drv, OID_802_11_DEAUTHENTICATION,
- (char *) &mlme,
- sizeof(MLME_DEAUTH_REQ_STRUCT));
- }
-}
-
-static int wpa_driver_ralink_set_gen_ie(void *priv, const u8 *ie,
- size_t ie_len)
-{
- struct wpa_driver_ralink_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.data.pointer = (caddr_t) ie;
- iwr.u.data.length = ie_len;
-
- wpa_hexdump(MSG_DEBUG, "wpa_driver_ralink_set_gen_ie: ",
- (u8 *) ie, ie_len);
-
- if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
- perror("ioctl[SIOCSIWGENIE]");
- ret = -1;
- }
-
- return ret;
-}
-
-static int
-wpa_driver_ralink_associate(void *priv,
- struct wpa_driver_associate_params *params)
-{
- struct wpa_driver_ralink_data *drv = priv;
-
- NDIS_802_11_NETWORK_INFRASTRUCTURE mode;
- NDIS_802_11_AUTHENTICATION_MODE auth_mode;
- NDIS_802_11_WEP_STATUS encr;
- BOOLEAN ieee8021xMode;
- BOOLEAN ieee8021x_required_key = TRUE;
-
- if (drv->g_driver_down == 1)
- return -1;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
- if (params->mode == IEEE80211_MODE_IBSS)
- mode = Ndis802_11IBSS;
- else
- mode = Ndis802_11Infrastructure;
-
- if (ralink_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
- (char *) &mode, sizeof(mode)) < 0) {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
- "OID_802_11_INFRASTRUCTURE_MODE (%d)",
- (int) mode);
- /* Try to continue anyway */
- }
-
- if (params->key_mgmt_suite == KEY_MGMT_WPS) {
- UCHAR enable_wps = 0x80;
- /* trigger driver support wpa_supplicant */
- if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
- (PCHAR) &enable_wps, sizeof(UCHAR)) < 0) {
- wpa_printf(MSG_INFO, "RALINK: Failed to set "
- "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
- (int) enable_wps);
- }
-
- wpa_driver_ralink_set_gen_ie(priv, params->wpa_ie,
- params->wpa_ie_len);
-
- ralink_set_auth_mode(drv, Ndis802_11AuthModeOpen);
-
- ralink_set_encr_type(drv, Ndis802_11EncryptionDisabled);
- } else {
-#ifdef CONFIG_WPS
- UCHAR enable_wpa_supplicant;
-
- if (drv->ap_scan == 1)
- enable_wpa_supplicant = 0x01;
- else
- enable_wpa_supplicant = 0x02;
-
- /* trigger driver support wpa_supplicant */
- if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
- (PCHAR) &enable_wpa_supplicant,
- sizeof(UCHAR)) < 0) {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
- "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
- (int) enable_wpa_supplicant);
- }
-
- wpa_driver_ralink_set_gen_ie(priv, (u8 *) "", 0);
-#endif /* CONFIG_WPS */
-
- if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
- if (params->auth_alg & WPA_AUTH_ALG_SHARED) {
- if (params->auth_alg & WPA_AUTH_ALG_OPEN)
- auth_mode = Ndis802_11AuthModeAutoSwitch;
- else
- auth_mode = Ndis802_11AuthModeShared;
- } else
- auth_mode = Ndis802_11AuthModeOpen;
- } else if (params->wpa_ie[0] == WLAN_EID_RSN) {
- if (params->key_mgmt_suite == KEY_MGMT_PSK)
- auth_mode = Ndis802_11AuthModeWPA2PSK;
- else
- auth_mode = Ndis802_11AuthModeWPA2;
- } else {
- if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
- auth_mode = Ndis802_11AuthModeWPANone;
- else if (params->key_mgmt_suite == KEY_MGMT_PSK)
- auth_mode = Ndis802_11AuthModeWPAPSK;
- else
- auth_mode = Ndis802_11AuthModeWPA;
- }
-
- switch (params->pairwise_suite) {
- case CIPHER_CCMP:
- encr = Ndis802_11Encryption3Enabled;
- break;
- case CIPHER_TKIP:
- encr = Ndis802_11Encryption2Enabled;
- break;
- case CIPHER_WEP40:
- case CIPHER_WEP104:
- encr = Ndis802_11Encryption1Enabled;
- break;
- case CIPHER_NONE:
- if (params->group_suite == CIPHER_CCMP)
- encr = Ndis802_11Encryption3Enabled;
- else if (params->group_suite == CIPHER_TKIP)
- encr = Ndis802_11Encryption2Enabled;
- else
- encr = Ndis802_11EncryptionDisabled;
- break;
- default:
- encr = Ndis802_11EncryptionDisabled;
- break;
- }
-
- ralink_set_auth_mode(drv, auth_mode);
-
- /* notify driver that IEEE8021x mode is enabled */
- if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
- ieee8021xMode = TRUE;
- if (drv->bAddWepKey)
- ieee8021x_required_key = FALSE;
- } else
- ieee8021xMode = FALSE;
-
- if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY,
- (char *) &ieee8021x_required_key,
- sizeof(BOOLEAN)) < 0) {
- wpa_printf(MSG_DEBUG, "ERROR: Failed to set "
- "OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)",
- (int) ieee8021x_required_key);
- } else {
- wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s",
- ieee8021x_required_key ? "TRUE" : "FALSE");
- }
-
- if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X,
- (char *) &ieee8021xMode, sizeof(BOOLEAN)) <
- 0) {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
- "OID_802_11_SET_IEEE8021X(%d)",
- (int) ieee8021xMode);
- }
-
- ralink_set_encr_type(drv, encr);
-
- if ((ieee8021xMode == FALSE) &&
- (encr == Ndis802_11Encryption1Enabled)) {
- /* static WEP */
- int enabled = 0;
- if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED,
- (char *) &enabled, sizeof(enabled))
- < 0) {
- wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
- "OID_802_11_DROP_UNENCRYPTED(%d)",
- (int) encr);
- }
- }
- }
-
- return wpa_driver_ralink_set_ssid(drv, params->ssid, params->ssid_len);
-}
-
-static int
-wpa_driver_ralink_set_countermeasures(void *priv, int enabled)
-{
- struct wpa_driver_ralink_data *drv = priv;
- if (drv->g_driver_down == 1)
- return -1;
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
- return ralink_set_oid(drv, OID_SET_COUNTERMEASURES, (char *) &enabled,
- sizeof(int));
-}
-
-const struct wpa_driver_ops wpa_driver_ralink_ops = {
- .name = "ralink",
- .desc = "Ralink Wireless Client driver",
- .get_bssid = wpa_driver_ralink_get_bssid,
- .get_ssid = wpa_driver_ralink_get_ssid,
- .set_key = wpa_driver_ralink_set_key,
- .init = wpa_driver_ralink_init,
- .deinit = wpa_driver_ralink_deinit,
- .set_countermeasures = wpa_driver_ralink_set_countermeasures,
- .scan2 = wpa_driver_ralink_scan,
- .get_scan_results2 = wpa_driver_ralink_get_scan_results,
- .deauthenticate = wpa_driver_ralink_deauthenticate,
- .disassociate = wpa_driver_ralink_disassociate,
- .associate = wpa_driver_ralink_associate,
- .add_pmkid = wpa_driver_ralink_add_pmkid,
- .remove_pmkid = wpa_driver_ralink_remove_pmkid,
- .flush_pmkid = wpa_driver_ralink_flush_pmkid,
-};
diff --git a/src/drivers/driver_ralink.h b/src/drivers/driver_ralink.h
deleted file mode 100644
index d13df28..0000000
--- a/src/drivers/driver_ralink.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * WPA Supplicant - driver_ralink exported functions
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-// Ralink defined OIDs
-#if WIRELESS_EXT <= 11
-#ifndef SIOCDEVPRIVATE
-#define SIOCDEVPRIVATE 0x8BE0
-#endif
-#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
-#endif
-
-#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E)
-#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02)
-
-// IEEE 802.11 OIDs & Ralink defined OIDs ******
-
-// (RaConfig Set/QueryInform) ==>
-#define OID_GET_SET_TOGGLE 0x8000
-
-#define OID_802_11_ADD_WEP 0x0112
-#define OID_802_11_REMOVE_WEP 0x0113
-#define OID_802_11_DISASSOCIATE 0x0114
-#define OID_802_11_PRIVACY_FILTER 0x0118
-#define OID_802_11_ASSOCIATION_INFORMATION 0x011E
-#define OID_802_11_BSSID_LIST_SCAN 0x0508
-#define OID_802_11_SSID 0x0509
-#define OID_802_11_BSSID 0x050A
-#define OID_802_11_WEP_STATUS 0x0510
-#define OID_802_11_AUTHENTICATION_MODE 0x0511
-#define OID_802_11_INFRASTRUCTURE_MODE 0x0512
-#define OID_802_11_TX_POWER_LEVEL 0x0517
-#define OID_802_11_REMOVE_KEY 0x0519
-#define OID_802_11_ADD_KEY 0x0520
-#define OID_802_11_DEAUTHENTICATION 0x0526
-#define OID_802_11_DROP_UNENCRYPTED 0x0527
-#define OID_802_11_BSSID_LIST 0x0609
-#define OID_802_3_CURRENT_ADDRESS 0x060A
-#define OID_SET_COUNTERMEASURES 0x0616
-#define OID_802_11_SET_IEEE8021X 0x0617 // For IEEE8021x mode
-#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 // For DynamicWEP in IEEE802.1x mode
-#define OID_802_11_PMKID 0x0620
-#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 // for trigger driver enable/disable wpa_supplicant support
-#define RT_OID_WE_VERSION_COMPILED 0x0622
-#define RT_OID_NEW_DRIVER 0x0623
-#define RT_OID_WPS_PROBE_REQ_IE 0x0625
-
-#define PACKED __attribute__ ((packed))
-
-//wpa_supplicant event flags
-#define RT_ASSOC_EVENT_FLAG 0x0101
-#define RT_DISASSOC_EVENT_FLAG 0x0102
-#define RT_REQIE_EVENT_FLAG 0x0103
-#define RT_RESPIE_EVENT_FLAG 0x0104
-#define RT_ASSOCINFO_EVENT_FLAG 0x0105
-#define RT_PMKIDCAND_FLAG 0x0106
-#define RT_INTERFACE_DOWN 0x0107
-#define RT_INTERFACE_UP 0x0108
-
-//
-// IEEE 802.11 Structures and definitions
-//
-// new types for Media Specific Indications
-
-#ifndef ULONG
-#define CHAR char
-#define INT int
-#define SHORT int
-#define UINT u32
-#undef ULONG
-//#define ULONG u32
-#define ULONG unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */
-#define USHORT unsigned short
-#define UCHAR unsigned char
-
-#define uint32 u32
-#define uint8 u8
-
-
-#define BOOLEAN u8
-//#define LARGE_INTEGER s64
-#define VOID void
-#define LONG long
-#define LONGLONG s64
-#define ULONGLONG u64
-typedef VOID *PVOID;
-typedef CHAR *PCHAR;
-typedef UCHAR *PUCHAR;
-typedef USHORT *PUSHORT;
-typedef LONG *PLONG;
-typedef ULONG *PULONG;
-
-typedef union _LARGE_INTEGER {
- struct {
- ULONG LowPart;
- LONG HighPart;
- }vv;
- struct {
- ULONG LowPart;
- LONG HighPart;
- } u;
- s64 QuadPart;
-} LARGE_INTEGER;
-
-#endif
-
-#define NDIS_802_11_LENGTH_SSID 32
-#define NDIS_802_11_LENGTH_RATES 8
-#define NDIS_802_11_LENGTH_RATES_EX 16
-#define MAX_LEN_OF_SSID 32
-#define MAC_ADDR_LEN 6
-
-typedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
-
-// mask for authentication/integrity fields
-#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f
-
-#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01
-#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02
-#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06
-#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E
-
-// Added new types for OFDM 5G and 2.4G
-typedef enum _NDIS_802_11_NETWORK_TYPE
-{
- Ndis802_11FH,
- Ndis802_11DS,
- Ndis802_11OFDM5,
- Ndis802_11OFDM24,
- Ndis802_11Automode,
- Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound
-} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE;
-
-//
-// Received Signal Strength Indication
-//
-typedef LONG NDIS_802_11_RSSI; // in dBm
-
-typedef struct _NDIS_802_11_CONFIGURATION_FH
-{
- ULONG Length; // Length of structure
- ULONG HopPattern; // As defined by 802.11, MSB set
- ULONG HopSet; // to one if non-802.11
- ULONG DwellTime; // units are Kusec
-} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH;
-
-typedef struct _NDIS_802_11_CONFIGURATION
-{
- ULONG Length; // Length of structure
- ULONG BeaconPeriod; // units are Kusec
- ULONG ATIMWindow; // units are Kusec
- ULONG DSConfig; // Frequency, units are kHz
- NDIS_802_11_CONFIGURATION_FH FHConfig;
-} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION;
-
-typedef ULONG NDIS_802_11_KEY_INDEX;
-typedef ULONGLONG NDIS_802_11_KEY_RSC;
-
-// Key mapping keys require a BSSID
-typedef struct _NDIS_802_11_KEY
-{
- UINT Length; // Length of this structure
- UINT KeyIndex;
- UINT KeyLength; // length of key in bytes
- NDIS_802_11_MAC_ADDRESS BSSID;
- NDIS_802_11_KEY_RSC KeyRSC;
- UCHAR KeyMaterial[1]; // variable length depending on above field
-} NDIS_802_11_KEY, *PNDIS_802_11_KEY;
-
-typedef struct _NDIS_802_11_REMOVE_KEY
-{
- UINT Length; // Length of this structure
- UINT KeyIndex;
- NDIS_802_11_MAC_ADDRESS BSSID;
-} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY;
-
-typedef struct PACKED _NDIS_802_11_WEP
-{
- UINT Length; // Length of this structure
- UINT KeyIndex; // 0 is the per-client key, 1-N are the
- // global keys
- UINT KeyLength; // length of key in bytes
- UCHAR KeyMaterial[1];// variable length depending on above field
-} NDIS_802_11_WEP, *PNDIS_802_11_WEP;
-
-
-typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE
-{
- Ndis802_11IBSS,
- Ndis802_11Infrastructure,
- Ndis802_11AutoUnknown,
- Ndis802_11InfrastructureMax // Not a real value, defined as upper bound
-} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE;
-
-// PMKID Structures
-typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
-
-typedef struct _BSSID_INFO
-{
- NDIS_802_11_MAC_ADDRESS BSSID;
- NDIS_802_11_PMKID_VALUE PMKID;
-} BSSID_INFO, *PBSSID_INFO;
-
-typedef struct _NDIS_802_11_PMKID
-{
- ULONG Length;
- ULONG BSSIDInfoCount;
- BSSID_INFO BSSIDInfo[1];
-} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID;
-
-//Added new types for PMKID Candidate lists.
-typedef struct _PMKID_CANDIDATE {
- NDIS_802_11_MAC_ADDRESS BSSID;
- ULONG Flags;
-} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
-
-typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST
-{
- ULONG Version; // Version of the structure
- ULONG NumCandidates; // No. of pmkid candidates
- PMKID_CANDIDATE CandidateList[1];
-} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST;
-
-//Flags for PMKID Candidate list structure
-#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
-
-// Add new authentication modes
-typedef enum _NDIS_802_11_AUTHENTICATION_MODE
-{
- Ndis802_11AuthModeOpen,
- Ndis802_11AuthModeShared,
- Ndis802_11AuthModeAutoSwitch,
- Ndis802_11AuthModeWPA,
- Ndis802_11AuthModeWPAPSK,
- Ndis802_11AuthModeWPANone,
- Ndis802_11AuthModeWPA2,
- Ndis802_11AuthModeWPA2PSK,
- Ndis802_11AuthModeMax // Not a real mode, defined as upper bound
-} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE;
-
-typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates
-typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates
-
-typedef struct PACKED _NDIS_802_11_SSID
-{
- INT SsidLength; // length of SSID field below, in bytes;
- // this can be zero.
- UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field
-} NDIS_802_11_SSID, *PNDIS_802_11_SSID;
-
-
-typedef struct PACKED _NDIS_WLAN_BSSID
-{
- ULONG Length; // Length of this structure
- NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
- UCHAR Reserved[2];
- NDIS_802_11_SSID Ssid; // SSID
- ULONG Privacy; // WEP encryption requirement
- NDIS_802_11_RSSI Rssi; // receive signal
- // strength in dBm
- NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
- NDIS_802_11_CONFIGURATION Configuration;
- NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
- NDIS_802_11_RATES SupportedRates;
-} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;
-
-typedef struct PACKED _NDIS_802_11_BSSID_LIST
-{
- UINT NumberOfItems; // in list below, at least 1
- NDIS_WLAN_BSSID Bssid[1];
-} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
-
-// Added Capabilities, IELength and IEs for each BSSID
-typedef struct PACKED _NDIS_WLAN_BSSID_EX
-{
- ULONG Length; // Length of this structure
- NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
- UCHAR Reserved[2];
- NDIS_802_11_SSID Ssid; // SSID
- UINT Privacy; // WEP encryption requirement
- NDIS_802_11_RSSI Rssi; // receive signal
- // strength in dBm
- NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
- NDIS_802_11_CONFIGURATION Configuration;
- NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
- NDIS_802_11_RATES_EX SupportedRates;
- ULONG IELength;
- UCHAR IEs[1];
-} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX;
-
-typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX
-{
- UINT NumberOfItems; // in list below, at least 1
- NDIS_WLAN_BSSID_EX Bssid[1];
-} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX;
-
-typedef struct PACKED _NDIS_802_11_FIXED_IEs
-{
- UCHAR Timestamp[8];
- USHORT BeaconInterval;
- USHORT Capabilities;
-} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs;
-
-// Added new encryption types
-// Also aliased typedef to new name
-typedef enum _NDIS_802_11_WEP_STATUS
-{
- Ndis802_11WEPEnabled,
- Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
- Ndis802_11WEPDisabled,
- Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
- Ndis802_11WEPKeyAbsent,
- Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
- Ndis802_11WEPNotSupported,
- Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
- Ndis802_11Encryption2Enabled,
- Ndis802_11Encryption2KeyAbsent,
- Ndis802_11Encryption3Enabled,
- Ndis802_11Encryption3KeyAbsent
-} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
- NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
-
-typedef enum _NDIS_802_11_RELOAD_DEFAULTS
-{
- Ndis802_11ReloadWEPKeys
-} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS;
-
-#define NDIS_802_11_AI_REQFI_CAPABILITIES 1
-#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2
-#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4
-
-#define NDIS_802_11_AI_RESFI_CAPABILITIES 1
-#define NDIS_802_11_AI_RESFI_STATUSCODE 2
-#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4
-
-typedef struct _NDIS_802_11_AI_REQFI
-{
- USHORT Capabilities;
- USHORT ListenInterval;
- NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
-} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
-
-typedef struct _NDIS_802_11_AI_RESFI
-{
- USHORT Capabilities;
- USHORT StatusCode;
- USHORT AssociationId;
-} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
-
-typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
-{
- ULONG Length;
- USHORT AvailableRequestFixedIEs;
- NDIS_802_11_AI_REQFI RequestFixedIEs;
- ULONG RequestIELength;
- ULONG OffsetRequestIEs;
- USHORT AvailableResponseFixedIEs;
- NDIS_802_11_AI_RESFI ResponseFixedIEs;
- ULONG ResponseIELength;
- ULONG OffsetResponseIEs;
-} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
-
-struct ndis_pmkid_entry {
- struct ndis_pmkid_entry *next;
- u8 bssid[ETH_ALEN];
- u8 pmkid[16];
-};
-
-typedef struct _MLME_DEAUTH_REQ_STRUCT {
- UCHAR Addr[MAC_ADDR_LEN];
- USHORT Reason;
-} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT;
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index c014b96..61b75b1 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -364,7 +364,7 @@ static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname)
/* copy ifname and take a pointer to the second to last character */
sep = drv->ifname +
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2;
- /* find the '.' seperating <interface> and <vlan> */
+ /* find the '.' separating <interface> and <vlan> */
while (sep > drv->ifname && *sep != '.') sep--;
if (sep <= drv->ifname) {
wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in "
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 6bfa46d..f8e314b 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -89,7 +89,6 @@ struct wpa_driver_test_data {
int use_associnfo;
u8 assoc_wpa_ie[80];
size_t assoc_wpa_ie_len;
- int use_mlme;
int associated;
u8 *probe_req_ie;
size_t probe_req_ie_len;
@@ -117,6 +116,7 @@ struct wpa_driver_test_data {
u8 pending_action_dst[ETH_ALEN];
u8 pending_action_bssid[ETH_ALEN];
unsigned int pending_action_freq;
+ unsigned int pending_action_no_cck;
unsigned int pending_listen_freq;
unsigned int pending_listen_duration;
int pending_p2p_scan;
@@ -309,7 +309,7 @@ static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
- size_t data_len)
+ size_t data_len, int noack)
{
struct test_driver_bss *dbss = priv;
struct wpa_driver_test_data *drv = dbss->drv;
@@ -561,7 +561,7 @@ static void test_driver_scan(struct wpa_driver_test_data *drv,
wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event);
#ifdef CONFIG_P2P
if (drv->p2p)
- p2p_probe_req_rx(drv->p2p, sa, ie, ielen);
+ p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
#endif /* CONFIG_P2P */
}
@@ -1102,13 +1102,6 @@ static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type,
}
-static int test_driver_valid_bss_mask(void *priv, const u8 *addr,
- const u8 *mask)
-{
- return 0;
-}
-
-
static int test_driver_set_ssid(void *priv, const u8 *buf, int len)
{
struct test_driver_bss *bss = priv;
@@ -1232,6 +1225,7 @@ static void * test_driver_init(struct hostapd_data *hapd,
return NULL;
drv->ap = 1;
bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+ drv->global = params->global_priv;
bss->bss_ctx = hapd;
os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN);
@@ -1966,6 +1960,8 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) {
os_memset(&event, 0, sizeof(event));
event.rx_probe_req.sa = mgmt->sa;
+ event.rx_probe_req.da = mgmt->da;
+ event.rx_probe_req.bssid = mgmt->bssid;
event.rx_probe_req.ie = mgmt->u.probe_req.variable;
event.rx_probe_req.ie_len =
data_len - (mgmt->u.probe_req.variable - data);
@@ -1974,6 +1970,7 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
#ifdef CONFIG_P2P
if (drv->p2p)
p2p_probe_req_rx(drv->p2p, mgmt->sa,
+ mgmt->da, mgmt->bssid,
event.rx_probe_req.ie,
event.rx_probe_req.ie_len);
#endif /* CONFIG_P2P */
@@ -2028,7 +2025,7 @@ static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv,
ielen = 0;
drv->probe_from = from;
drv->probe_from_len = fromlen;
- p2p_probe_req_rx(drv->p2p, sa, ie, ielen);
+ p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
drv->probe_from = NULL;
}
#endif /* CONFIG_P2P */
@@ -2390,13 +2387,6 @@ static int wpa_driver_test_set_param(void *priv, const char *param)
drv->use_associnfo = 1;
}
-#ifdef CONFIG_CLIENT_MLME
- if (os_strstr(param, "use_mlme=1")) {
- wpa_printf(MSG_DEBUG, "test_driver: Use internal MLME");
- drv->use_mlme = 1;
- }
-#endif /* CONFIG_CLIENT_MLME */
-
if (os_strstr(param, "p2p_mgmt=1")) {
wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P "
"management");
@@ -2510,8 +2500,6 @@ static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
capa->auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
- if (drv->use_mlme)
- capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
if (drv->p2p)
capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT;
capa->flags |= WPA_DRIVER_FLAGS_AP;
@@ -2541,50 +2529,6 @@ static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr,
}
-static int wpa_driver_test_set_channel(void *priv,
- enum hostapd_hw_mode phymode,
- int chan, int freq)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d",
- __func__, phymode, chan, freq);
- drv->current_freq = freq;
- return 0;
-}
-
-
-static int wpa_driver_test_mlme_add_sta(void *priv, const u8 *addr,
- const u8 *supp_rates,
- size_t supp_rates_len)
-{
- wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
- return 0;
-}
-
-
-static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr)
-{
- wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
- return 0;
-}
-
-
-static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid,
- size_t ssid_len)
-{
- wpa_printf(MSG_DEBUG, "%s", __func__);
- return 0;
-}
-
-
-static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
-{
- wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid));
- return 0;
-}
-
-
static void * wpa_driver_test_global_init(void)
{
struct wpa_driver_test_global *global;
@@ -2727,7 +2671,8 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq,
unsigned int wait,
const u8 *dst, const u8 *src,
const u8 *bssid,
- const u8 *data, size_t data_len)
+ const u8 *data, size_t data_len,
+ int no_cck)
{
struct test_driver_bss *dbss = priv;
struct wpa_driver_test_data *drv = dbss->drv;
@@ -2760,7 +2705,7 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq,
os_memcpy(hdr->addr2, src, ETH_ALEN);
os_memcpy(hdr->addr3, bssid, ETH_ALEN);
- ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len);
+ ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len, 0);
os_free(buf);
return ret;
}
@@ -2770,7 +2715,6 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq,
static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_driver_test_data *drv = eloop_ctx;
- int res;
if (drv->pending_action_tx == NULL)
return;
@@ -2783,12 +2727,13 @@ static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx)
}
wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
MACSTR, MAC2STR(drv->pending_action_dst));
- res = wpa_driver_test_send_action(drv, drv->pending_action_freq, 0,
- drv->pending_action_dst,
- drv->pending_action_src,
- drv->pending_action_bssid,
- wpabuf_head(drv->pending_action_tx),
- wpabuf_len(drv->pending_action_tx));
+ wpa_driver_test_send_action(drv, drv->pending_action_freq, 0,
+ drv->pending_action_dst,
+ drv->pending_action_src,
+ drv->pending_action_bssid,
+ wpabuf_head(drv->pending_action_tx),
+ wpabuf_len(drv->pending_action_tx),
+ drv->pending_action_no_cck);
}
#endif /* CONFIG_P2P */
@@ -2980,6 +2925,7 @@ static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
int ret;
struct wpabuf *wps_ie, *ies;
int social_channels[] = { 2412, 2437, 2462, 0, 0 };
+ size_t ielen;
wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)",
__func__, type, freq);
@@ -3001,7 +2947,8 @@ static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
if (wps_ie == NULL)
return -1;
- ies = wpabuf_alloc(wpabuf_len(wps_ie) + 100);
+ ielen = p2p_scan_ie_buf_len(drv->p2p);
+ ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
if (ies == NULL) {
wpabuf_free(wps_ie);
return -1;
@@ -3069,6 +3016,7 @@ static int test_send_action(void *ctx, unsigned int freq, const u8 *dst,
os_memcpy(drv->pending_action_dst, dst, ETH_ALEN);
os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN);
drv->pending_action_freq = freq;
+ drv->pending_action_no_cck = 1;
if (drv->off_channel_freq == freq) {
/* Already on requested channel; send immediately */
@@ -3248,7 +3196,8 @@ static void test_sd_response(void *ctx, const u8 *sa, u16 update_indic,
static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
const u8 *dev_addr, const u8 *pri_dev_type,
const char *dev_name, u16 supp_config_methods,
- u8 dev_capab, u8 group_capab)
+ u8 dev_capab, u8 group_capab,
+ const u8 *group_id, size_t group_id_len)
{
wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)",
__func__, MAC2STR(peer), config_methods);
@@ -3343,7 +3292,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
.get_hw_feature_data = wpa_driver_test_get_hw_feature_data,
.if_add = test_driver_if_add,
.if_remove = test_driver_if_remove,
- .valid_bss_mask = test_driver_valid_bss_mask,
.hapd_set_ssid = test_driver_set_ssid,
.set_privacy = test_driver_set_privacy,
.set_sta_vlan = test_driver_set_sta_vlan,
@@ -3362,11 +3310,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
.get_mac_addr = wpa_driver_test_get_mac_addr,
.send_eapol = wpa_driver_test_send_eapol,
.mlme_setprotection = wpa_driver_test_mlme_setprotection,
- .set_channel = wpa_driver_test_set_channel,
- .set_ssid = wpa_driver_test_set_ssid,
- .set_bssid = wpa_driver_test_set_bssid,
- .mlme_add_sta = wpa_driver_test_mlme_add_sta,
- .mlme_remove_sta = wpa_driver_test_mlme_remove_sta,
.get_scan_results2 = wpa_driver_test_get_scan_results2,
.global_init = wpa_driver_test_global_init,
.global_deinit = wpa_driver_test_global_deinit,
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 001716e..381cb3e 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -25,7 +25,7 @@
#include <fcntl.h>
#include <net/if_arp.h>
-#include "wireless_copy.h"
+#include "linux_wext.h"
#include "common.h"
#include "eloop.h"
#include "common/ieee802_11_defs.h"
@@ -37,6 +37,9 @@
#include "driver.h"
#include "driver_wext.h"
+#ifdef ANDROID
+#include "android_drv.h"
+#endif /* ANDROID */
static int wpa_driver_wext_flush_pmkid(void *priv);
static int wpa_driver_wext_get_range(void *priv);
@@ -842,12 +845,13 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
}
drv->mlme_sock = -1;
+
#ifdef ANDROID
drv->errors = 0;
drv->driver_is_started = TRUE;
drv->skip_disconnect = 0;
drv->bgscan_enabled = 0;
-#endif
+#endif /* ANDROID */
if (wpa_driver_wext_finish_drv_init(drv) < 0)
goto err3;
@@ -1416,7 +1420,7 @@ static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
tmp[res->num++] = r;
res->res = tmp;
}
-
+
/**
* wpa_driver_wext_get_scan_results - Fetch the latest scan results
@@ -1426,7 +1430,7 @@ static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
{
struct wpa_driver_wext_data *drv = priv;
- size_t ap_num = 0, len;
+ size_t len;
int first;
u8 *res_buf;
struct iw_event iwe_buf, *iwe = &iwe_buf;
@@ -1438,7 +1442,6 @@ struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
if (res_buf == NULL)
return NULL;
- ap_num = 0;
first = 1;
res = os_zalloc(sizeof(*res));
@@ -1868,8 +1871,10 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
{
struct iwreq iwr;
const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+#ifndef ANDROID
u8 ssid[32];
int i;
+#endif /* ANDROID */
/*
* Only force-disconnect when the card is in infrastructure mode,
@@ -1884,40 +1889,39 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
}
if (iwr.u.mode == IW_MODE_INFRA) {
+ /* Clear the BSSID selection */
+ if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID "
+ "selection on disconnect");
+ }
+
+#ifndef ANDROID
if (drv->cfg80211) {
/*
* cfg80211 supports SIOCSIWMLME commands, so there is
* no need for the random SSID hack, but clear the
- * BSSID and SSID.
+ * SSID.
*/
- if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
-#ifdef ANDROID
- 0) {
-#else
- wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
-#endif
+ if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
- "to disconnect");
+ "SSID on disconnect");
}
return;
}
+
/*
- * Clear the BSSID selection and set a random SSID to make sure
- * the driver will not be trying to associate with something
- * even if it does not understand SIOCSIWMLME commands (or
- * tries to associate automatically after deauth/disassoc).
+ * Set a random SSID to make sure the driver will not be trying
+ * to associate with something even if it does not understand
+ * SIOCSIWMLME commands (or tries to associate automatically
+ * after deauth/disassoc).
*/
for (i = 0; i < 32; i++)
ssid[i] = rand() & 0xFF;
- if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
-#ifdef ANDROID
- 0) {
-#else
- wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
-#endif
+ if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
- "BSSID/SSID to disconnect");
+ "SSID to disconnect");
}
+#endif /* ANDROID */
}
}
@@ -2350,6 +2354,129 @@ static const char * wext_get_radio_name(void *priv)
}
+#ifdef ANDROID
+
+static int android_wext_cmd(struct wpa_driver_wext_data *drv, const char *cmd)
+{
+ struct iwreq iwr;
+ char buf[MAX_DRV_CMD_SIZE];
+ int ret;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ os_memset(buf, 0, sizeof(buf));
+ os_strlcpy(buf, cmd, sizeof(buf));
+
+ iwr.u.data.pointer = buf;
+ iwr.u.data.length = sizeof(buf);
+
+ ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret,
+ cmd);
+ drv->errors++;
+ if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+ drv->errors = 0;
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE
+ "HANGED");
+ }
+ return ret;
+ }
+
+ drv->errors = 0;
+ return 0;
+}
+
+
+static int wext_sched_scan(void *priv, struct wpa_driver_scan_params *params,
+ u32 interval)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0, i = 0, bp;
+ char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+ bp = WEXT_PNOSETUP_HEADER_SIZE;
+ os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+ buf[bp++] = WEXT_PNO_TLV_PREFIX;
+ buf[bp++] = WEXT_PNO_TLV_VERSION;
+ buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+ buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+ while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+ /*
+ * Check that there is enough space needed for 1 more SSID, the
+ * other sections and null termination.
+ */
+ if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE +
+ WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+ break;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+ params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ buf[bp++] = WEXT_PNO_SSID_SECTION;
+ buf[bp++] = params->ssids[i].ssid_len;
+ os_memcpy(&buf[bp], params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ bp += params->ssids[i].ssid_len;
+ i++;
+ }
+
+ buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+ /* TODO: consider using interval parameter (interval in msec) instead
+ * of hardcoded value here */
+ os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+ WEXT_PNO_SCAN_INTERVAL);
+ bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+ buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+ WEXT_PNO_REPEAT);
+ bp += WEXT_PNO_REPEAT_LENGTH;
+
+ buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+ WEXT_PNO_MAX_REPEAT);
+ bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = buf;
+ iwr.u.data.length = bp;
+
+ ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+ ret);
+ drv->errors++;
+ if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+ drv->errors = 0;
+ wpa_msg(drv->ctx, MSG_INFO,
+ WPA_EVENT_DRIVER_STATE "HANGED");
+ }
+ return ret;
+ }
+
+ drv->errors = 0;
+ drv->bgscan_enabled = 1;
+
+ return android_wext_cmd(drv, "PNOFORCE 1");
+}
+
+
+static int wext_stop_sched_scan(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ drv->bgscan_enabled = 0;
+ return android_wext_cmd(drv, "PNOFORCE 0");
+}
+
+#endif /* ANDROID */
+
+
const struct wpa_driver_ops wpa_driver_wext_ops = {
.name = "wext",
.desc = "Linux wireless extensions (generic)",
@@ -2371,7 +2498,7 @@ const struct wpa_driver_ops wpa_driver_wext_ops = {
.set_operstate = wpa_driver_wext_set_operstate,
.get_radio_name = wext_get_radio_name,
#ifdef ANDROID
- .signal_poll = wpa_driver_signal_poll,
- .driver_cmd = wpa_driver_wext_driver_cmd,
-#endif
+ .sched_scan = wext_sched_scan,
+ .stop_sched_scan = wext_stop_sched_scan,
+#endif /* ANDROID */
};
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index 51e4d98..03df8e4 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -50,12 +50,13 @@ struct wpa_driver_wext_data {
int cfg80211; /* whether driver is using cfg80211 */
u8 max_level;
+
#ifdef ANDROID
int errors;
int driver_is_started;
int skip_disconnect;
int bgscan_enabled;
-#endif
+#endif /* ANDROID */
};
int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
@@ -90,9 +91,4 @@ int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
int wpa_driver_wext_cipher2wext(int cipher);
int wpa_driver_wext_keymgmt2wext(int keymgmt);
-#ifdef ANDROID
-#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE "
-#define WEXT_CSCAN_AMOUNT 9
-#endif
-
#endif /* DRIVER_WEXT_H */
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index b710778..667ea22 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -27,9 +27,6 @@ extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
#ifdef CONFIG_DRIVER_MADWIFI
extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
#endif /* CONFIG_DRIVER_MADWIFI */
-#ifdef CONFIG_DRIVER_BROADCOM
-extern struct wpa_driver_ops wpa_driver_broadcom_ops; /* driver_broadcom.c */
-#endif /* CONFIG_DRIVER_BROADCOM */
#ifdef CONFIG_DRIVER_BSD
extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
#endif /* CONFIG_DRIVER_BSD */
@@ -42,15 +39,6 @@ extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
#ifdef CONFIG_DRIVER_TEST
extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
#endif /* CONFIG_DRIVER_TEST */
-#ifdef CONFIG_DRIVER_RALINK
-extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */
-#endif /* CONFIG_DRIVER_RALINK */
-#ifdef CONFIG_DRIVER_OSX
-extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */
-#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_IPHONE
-extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
-#endif /* CONFIG_DRIVER_IPHONE */
#ifdef CONFIG_DRIVER_ROBOSWITCH
/* driver_roboswitch.c */
extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
@@ -77,9 +65,6 @@ struct wpa_driver_ops *wpa_drivers[] =
#ifdef CONFIG_DRIVER_MADWIFI
&wpa_driver_madwifi_ops,
#endif /* CONFIG_DRIVER_MADWIFI */
-#ifdef CONFIG_DRIVER_BROADCOM
- &wpa_driver_broadcom_ops,
-#endif /* CONFIG_DRIVER_BROADCOM */
#ifdef CONFIG_DRIVER_BSD
&wpa_driver_bsd_ops,
#endif /* CONFIG_DRIVER_BSD */
@@ -92,15 +77,6 @@ struct wpa_driver_ops *wpa_drivers[] =
#ifdef CONFIG_DRIVER_TEST
&wpa_driver_test_ops,
#endif /* CONFIG_DRIVER_TEST */
-#ifdef CONFIG_DRIVER_RALINK
- &wpa_driver_ralink_ops,
-#endif /* CONFIG_DRIVER_RALINK */
-#ifdef CONFIG_DRIVER_OSX
- &wpa_driver_osx_ops,
-#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_IPHONE
- &wpa_driver_iphone_ops,
-#endif /* CONFIG_DRIVER_IPHONE */
#ifdef CONFIG_DRIVER_ROBOSWITCH
&wpa_driver_roboswitch_ops,
#endif /* CONFIG_DRIVER_ROBOSWITCH */
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index ebf39c8..0cc81f9 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -12,29 +12,11 @@ DRV_AP_LIBS =
##### COMMON DRIVERS
-ifdef CONFIG_DRIVER_HOSTAP
-DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP
-DRV_OBJS += ../src/drivers/driver_hostap.o
-CONFIG_WIRELESS_EXTENSION=y
-NEED_AP_MLME=y
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
ifdef CONFIG_DRIVER_WIRED
DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
DRV_OBJS += ../src/drivers/driver_wired.o
endif
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_OBJS += ../src/drivers/driver_madwifi.o
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
ifdef CONFIG_DRIVER_NL80211
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
DRV_OBJS += ../src/drivers/driver_nl80211.o
@@ -44,15 +26,22 @@ NEED_AP_MLME=y
NEED_NETLINK=y
NEED_LINUX_IOCTL=y
NEED_RFKILL=y
-ifdef CONFIG_LIBNL_TINY
-DRV_LIBS += -lnl-tiny
+
+ifdef CONFIG_LIBNL32
+ DRV_LIBS += -lnl-3
+ DRV_LIBS += -lnl-genl-3
+ DRV_CFLAGS += -DCONFIG_LIBNL20
else
-DRV_LIBS += -lnl
-endif
+ ifdef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-tiny
+ else
+ DRV_LIBS += -lnl
+ endif
-ifdef CONFIG_LIBNL20
-DRV_LIBS += -lnl-genl
-DRV_CFLAGS += -DCONFIG_LIBNL20
+ ifdef CONFIG_LIBNL20
+ DRV_LIBS += -lnl-genl
+ DRV_CFLAGS += -DCONFIG_LIBNL20
+ endif
endif
endif
@@ -79,6 +68,24 @@ endif
##### PURE AP DRIVERS
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += ../src/drivers/driver_hostap.o
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
+DRV_AP_OBJS += ../src/drivers/driver_madwifi.o
+CONFIG_WIRELESS_EXTENSION=y
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
ifdef CONFIG_DRIVER_ATHEROS
DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
DRV_AP_OBJS += ../src/drivers/driver_atheros.o
@@ -97,18 +104,6 @@ NEED_LINUX_IOCTL=y
NEED_RFKILL=y
endif
-ifdef CONFIG_DRIVER_RALINK
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK
-DRV_WPA_OBJS += ../src/drivers/driver_ralink.o
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
-ifdef CONFIG_DRIVER_BROADCOM
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM
-DRV_WPA_OBJS += ../src/drivers/driver_broadcom.o
-endif
-
ifdef CONFIG_DRIVER_NDIS
DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
DRV_WPA_OBJS += ../src/drivers/driver_ndis.o
@@ -124,20 +119,6 @@ DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO
endif
endif
-ifdef CONFIG_DRIVER_OSX
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX
-DRV_WPA_OBJS += ../src/drivers/driver_osx.o
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
-endif
-
-ifdef CONFIG_DRIVER_IPHONE
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE
-DRV_WPA_OBJS += ../src/drivers/driver_iphone.o
-DRV_WPA_OBJS += ../src/drivers/MobileApple80211.o
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-endif
-
ifdef CONFIG_DRIVER_ROBOSWITCH
DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index c690e1c..1d7129c 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -12,29 +12,11 @@ DRV_AP_LIBS =
##### COMMON DRIVERS
-ifdef CONFIG_DRIVER_HOSTAP
-DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP
-DRV_OBJS += src/drivers/driver_hostap.c
-CONFIG_WIRELESS_EXTENSION=y
-NEED_AP_MLME=y
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
ifdef CONFIG_DRIVER_WIRED
DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
DRV_OBJS += src/drivers/driver_wired.c
endif
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_OBJS += src/drivers/driver_madwifi.c
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
ifdef CONFIG_DRIVER_NL80211
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
DRV_OBJS += src/drivers/driver_nl80211.c
@@ -44,15 +26,22 @@ NEED_AP_MLME=y
NEED_NETLINK=y
NEED_LINUX_IOCTL=y
NEED_RFKILL=y
-ifdef CONFIG_LIBNL_TINY
-DRV_LIBS += -lnl-tiny
+
+ifdef CONFIG_LIBNL32
+ DRV_LIBS += -lnl-3
+ DRV_LIBS += -lnl-genl-3
+ DRV_CFLAGS += -DCONFIG_LIBNL20
else
-DRV_LIBS += -lnl
-endif
+ ifdef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-tiny
+ else
+ DRV_LIBS += -lnl
+ endif
-ifdef CONFIG_LIBNL20
-DRV_LIBS += -lnl-genl
-DRV_CFLAGS += -DCONFIG_LIBNL20
+ ifdef CONFIG_LIBNL20
+ DRV_LIBS += -lnl-genl
+ DRV_CFLAGS += -DCONFIG_LIBNL20
+ endif
endif
endif
@@ -79,6 +68,24 @@ endif
##### PURE AP DRIVERS
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += src/drivers/driver_hostap.c
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
+DRV_AP_OBJS += src/drivers/driver_madwifi.c
+CONFIG_WIRELESS_EXTENSION=y
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
ifdef CONFIG_DRIVER_ATHEROS
DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
DRV_AP_OBJS += src/drivers/driver_atheros.c
@@ -97,18 +104,6 @@ NEED_LINUX_IOCTL=y
NEED_RFKILL=y
endif
-ifdef CONFIG_DRIVER_RALINK
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK
-DRV_WPA_OBJS += src/drivers/driver_ralink.c
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
-ifdef CONFIG_DRIVER_BROADCOM
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM
-DRV_WPA_OBJS += src/drivers/driver_broadcom.c
-endif
-
ifdef CONFIG_DRIVER_NDIS
DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
DRV_WPA_OBJS += src/drivers/driver_ndis.c
@@ -124,20 +119,6 @@ DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO
endif
endif
-ifdef CONFIG_DRIVER_OSX
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX
-DRV_WPA_OBJS += src/drivers/driver_osx.c
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
-endif
-
-ifdef CONFIG_DRIVER_IPHONE
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE
-DRV_WPA_OBJS += src/drivers/driver_iphone.c
-DRV_WPA_OBJS += src/drivers/MobileApple80211.c
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-endif
-
ifdef CONFIG_DRIVER_ROBOSWITCH
DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
DRV_WPA_OBJS += src/drivers/driver_roboswitch.c
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 0d6cf54..d7501cf 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -24,6 +24,7 @@
int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
{
struct ifreq ifr;
+ int ret;
if (sock < 0)
return -1;
@@ -32,9 +33,10 @@ int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+ ret = errno ? -errno : -999;
wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
ifname, strerror(errno));
- return -1;
+ return ret;
}
if (dev_up) {
@@ -48,15 +50,38 @@ int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
}
if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
+ ret = errno ? -errno : -999;
wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s",
ifname, strerror(errno));
- return -1;
+ return ret;
}
return 0;
}
+int linux_iface_up(int sock, const char *ifname)
+{
+ struct ifreq ifr;
+ int ret;
+
+ if (sock < 0)
+ return -1;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+ ret = errno ? -errno : -999;
+ wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
+ ifname, strerror(errno));
+ return ret;
+ }
+
+ return !!(ifr.ifr_flags & IFF_UP);
+}
+
+
int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
{
struct ifreq ifr;
diff --git a/src/drivers/linux_ioctl.h b/src/drivers/linux_ioctl.h
index a555738..e0bf673 100644
--- a/src/drivers/linux_ioctl.h
+++ b/src/drivers/linux_ioctl.h
@@ -16,6 +16,7 @@
#define LINUX_IOCTL_H
int linux_set_iface_flags(int sock, const char *ifname, int dev_up);
+int linux_iface_up(int sock, const char *ifname);
int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr);
int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr);
int linux_br_add(int sock, const char *brname);
diff --git a/src/drivers/linux_wext.h b/src/drivers/linux_wext.h
new file mode 100644
index 0000000..b6eea68
--- /dev/null
+++ b/src/drivers/linux_wext.h
@@ -0,0 +1,51 @@
+/*
+ * Driver interaction with generic Linux Wireless Extensions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef LINUX_WEXT_H
+#define LINUX_WEXT_H
+
+#ifndef ANDROID
+
+/*
+ * Avoid including other kernel header to avoid conflicts with C library
+ * headers.
+ */
+#define _LINUX_TYPES_H
+#define _LINUX_SOCKET_H
+#define _LINUX_IF_H
+
+#include <sys/types.h>
+#include <net/if.h>
+typedef __uint32_t __u32;
+typedef __int32_t __s32;
+typedef __uint16_t __u16;
+typedef __int16_t __s16;
+typedef __uint8_t __u8;
+#ifndef __user
+#define __user
+#endif /* __user */
+
+#endif /* ANDROID */
+
+#include <linux/wireless.h>
+
+#ifndef IW_ENCODE_ALG_PMK
+#define IW_ENCODE_ALG_PMK 4
+#endif
+
+#ifndef IW_ENC_CAPA_4WAY_HANDSHAKE
+#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010
+#endif
+
+#endif /* LINUX_WEXT_H */
diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c
index ad15b1d..6778907 100644
--- a/src/drivers/netlink.c
+++ b/src/drivers/netlink.c
@@ -34,7 +34,7 @@ static void netlink_receive_link(struct netlink_data *netlink,
if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg))
return;
cb(netlink->cfg->ctx, NLMSG_DATA(h),
- NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
+ (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
}
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 7483a89..f9261c2 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -6,7 +6,7 @@
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2008 Michael Wu <flamingice@sourmilk.net>
* Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
- * Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ * Copyright 2008 Michael Buesch <m@bues.ch>
* Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com>
@@ -77,6 +77,39 @@
*/
/**
+ * DOC: Virtual interface / concurrency capabilities
+ *
+ * Some devices are able to operate with virtual MACs, they can have
+ * more than one virtual interface. The capability handling for this
+ * is a bit complex though, as there may be a number of restrictions
+ * on the types of concurrency that are supported.
+ *
+ * To start with, each device supports the interface types listed in
+ * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the
+ * types there no concurrency is implied.
+ *
+ * Once concurrency is desired, more attributes must be observed:
+ * To start with, since some interface types are purely managed in
+ * software, like the AP-VLAN type in mac80211 for example, there's
+ * an additional list of these, they can be added at any time and
+ * are only restricted by some semantic restrictions (e.g. AP-VLAN
+ * cannot be added without a corresponding AP interface). This list
+ * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute.
+ *
+ * Further, the list of supported combinations is exported. This is
+ * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically,
+ * it exports a list of "groups", and at any point in time the
+ * interfaces that are currently active must fall into any one of
+ * the advertised groups. Within each group, there are restrictions
+ * on the number of interfaces of different types that are supported
+ * and also the number of different channels, along with potentially
+ * some other restrictions. See &enum nl80211_if_combination_attrs.
+ *
+ * All together, these attributes define the concurrency of virtual
+ * interfaces that a given device supports.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -128,6 +161,13 @@
* @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
* using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
* %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
+ * Following attributes are provided for drivers that generate full Beacon
+ * and Probe Response frames internally: %NL80211_ATTR_SSID,
+ * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
+ * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
+ * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
+ * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP,
+ * %NL80211_ATTR_IE_ASSOC_RESP.
* @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
* parameters are like for %NL80211_CMD_SET_BEACON.
* @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
@@ -148,6 +188,10 @@
* @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to
* destination %NL80211_ATTR_MAC on the interface identified by
* %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by
+ * %NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP.
+ * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by
+ * %NL80211_ATTR_MAC.
* @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
* the interface identified by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
@@ -172,10 +216,10 @@
* to the specified ISO/IEC 3166-1 alpha2 country code. The core will
* store this as a valid request and then query userspace for it.
*
- * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
+ * @NL80211_CMD_GET_MESH_CONFIG: Get mesh networking properties for the
* interface identified by %NL80211_ATTR_IFINDEX
*
- * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
+ * @NL80211_CMD_SET_MESH_CONFIG: Set mesh networking properties for the
* interface identified by %NL80211_ATTR_IFINDEX
*
* @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
@@ -194,11 +238,36 @@
*
* @NL80211_CMD_GET_SCAN: get scan results
* @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ * probe requests at CCK rate or not.
* @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
* NL80211_CMD_GET_SCAN and on the "scan" multicast group)
* @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
* partial scan results may be available
*
+ * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain
+ * intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL.
+ * Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS)
+ * are passed, they are used in the probe requests. For
+ * broadcast, a broadcast SSID must be passed (ie. an empty
+ * string). If no SSID is passed, no probe requests are sent and
+ * a passive scan is performed. %NL80211_ATTR_SCAN_FREQUENCIES,
+ * if passed, define which channels should be scanned; if not
+ * passed, all channels allowed for the current regulatory domain
+ * are used. Extra IEs can also be passed from the userspace by
+ * using the %NL80211_ATTR_IE attribute.
+ * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT
+ * if scheduled scan is not running.
+ * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan
+ * results available.
+ * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has
+ * stopped. The driver may issue this event at any time during a
+ * scheduled scan. One reason for stopping the scan is if the hardware
+ * does not support starting an association or a normal scan while running
+ * a scheduled scan. This event is also sent when the
+ * %NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface
+ * is brought down while a scheduled scan was running.
+ *
* @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
* or noise level
* @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
@@ -365,6 +434,8 @@
* specified using %NL80211_ATTR_DURATION. When called, this operation
* returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
* TX status event pertaining to the TX request.
+ * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ * management frames at CCK rate or not in 2GHz band.
* @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
* command may be used with the corresponding cookie to cancel the wait
* time if it is known that it is no longer necessary.
@@ -406,11 +477,72 @@
* notification. This event is used to indicate that an unprotected
* disassociation frame was dropped when MFP is in use.
*
+ * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
+ * beacon or probe response from a compatible mesh peer. This is only
+ * sent while no station information (sta_info) exists for the new peer
+ * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set. On
+ * reception of this notification, userspace may decide to create a new
+ * station (@NL80211_CMD_NEW_STATION). To stop this notification from
+ * reoccurring, the userspace authentication daemon may want to create the
+ * new station with the AUTHENTICATED flag unset and maybe change it later
+ * depending on the authentication result.
+ *
+ * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings.
+ * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings.
+ * Since wireless is more complex than wired ethernet, it supports
+ * various triggers. These triggers can be configured through this
+ * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
+ * more background information, see
+ * http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ *
+ * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
+ * the necessary information for supporting GTK rekey offload. This
+ * feature is typically used during WoWLAN. The configuration data
+ * is contained in %NL80211_ATTR_REKEY_DATA (which is nested and
+ * contains the data in sub-attributes). After rekeying happened,
+ * this command may also be sent by the driver as an MLME event to
+ * inform userspace of the new replay counter.
+ *
+ * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
+ * of PMKSA caching dandidates.
+ *
+ * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
+ *
+ * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
+ * (or GO) interface (i.e. hostapd) to ask for unexpected frames to
+ * implement sending deauth to stations that send unexpected class 3
+ * frames. Also used as the event sent by the kernel when such a frame
+ * is received.
+ * For the event, the %NL80211_ATTR_MAC attribute carries the TA and
+ * other attributes like the interface index are present.
+ * If used as the command it must have an interface index and you can
+ * only unsubscribe from the event by closing the socket. Subscription
+ * is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events.
+ *
+ * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the
+ * associated station identified by %NL80211_ATTR_MAC sent a 4addr frame
+ * and wasn't already in a 4-addr VLAN. The event will be sent similarly
+ * to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener.
+ *
+ * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
+ * by sending a null data frame to it and reporting when the frame is
+ * acknowleged. This is used to allow timing out inactive clients. Uses
+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
+ * direct reply with an %NL80211_ATTR_COOKIE that is later used to match
+ * up the event with the request. The event includes the same data and
+ * has %NL80211_ATTR_ACK set if the frame was ACKed.
+ *
+ * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
+ * other BSSes when any interfaces are in AP mode. This helps implement
+ * OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
+ * messages. Note that per PHY only one application may register.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
enum nl80211_commands {
-/* don't change the order or add anything inbetween, this is ABI! */
+/* don't change the order or add anything between, this is ABI! */
NL80211_CMD_UNSPEC,
NL80211_CMD_GET_WIPHY, /* can dump */
@@ -448,8 +580,8 @@ enum nl80211_commands {
NL80211_CMD_SET_REG,
NL80211_CMD_REQ_SET_REG,
- NL80211_CMD_GET_MESH_PARAMS,
- NL80211_CMD_SET_MESH_PARAMS,
+ NL80211_CMD_GET_MESH_CONFIG,
+ NL80211_CMD_SET_MESH_CONFIG,
NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,
@@ -518,6 +650,31 @@ enum nl80211_commands {
NL80211_CMD_UNPROT_DEAUTHENTICATE,
NL80211_CMD_UNPROT_DISASSOCIATE,
+ NL80211_CMD_NEW_PEER_CANDIDATE,
+
+ NL80211_CMD_GET_WOWLAN,
+ NL80211_CMD_SET_WOWLAN,
+
+ NL80211_CMD_START_SCHED_SCAN,
+ NL80211_CMD_STOP_SCHED_SCAN,
+ NL80211_CMD_SCHED_SCAN_RESULTS,
+ NL80211_CMD_SCHED_SCAN_STOPPED,
+
+ NL80211_CMD_SET_REKEY_OFFLOAD,
+
+ NL80211_CMD_PMKSA_CANDIDATE,
+
+ NL80211_CMD_TDLS_OPER,
+ NL80211_CMD_TDLS_MGMT,
+
+ NL80211_CMD_UNEXPECTED_FRAME,
+
+ NL80211_CMD_PROBE_CLIENT,
+
+ NL80211_CMD_REGISTER_BEACONS,
+
+ NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -538,6 +695,13 @@ enum nl80211_commands {
#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+
+/* source-level API compatibility */
+#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
+#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
+#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE
+
/**
* enum nl80211_attrs - nl80211 netlink attributes
*
@@ -608,7 +772,7 @@ enum nl80211_commands {
* consisting of a nested array.
*
* @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
- * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link.
* @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
* @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
* info given for %NL80211_CMD_GET_MPATH, nested attribute described at
@@ -653,8 +817,14 @@ enum nl80211_commands {
*
* @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
* a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: number of SSIDs you can
+ * scan with a single scheduled scan request, a wiphy attribute.
* @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
* that can be added to a scan request
+ * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information
+ * elements that can be added to a scheduled scan request
+ * @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be
+ * used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute.
*
* @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
* @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
@@ -735,18 +905,20 @@ enum nl80211_commands {
* @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
* event (u16)
* @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
- * that protected APs should be used.
+ * that protected APs should be used. This is also used with NEW_BEACON to
+ * indicate that the BSS is to use protection.
*
- * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
- * indicate which unicast key ciphers will be used with the connection
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON
+ * to indicate which unicast key ciphers will be used with the connection
* (an array of u32).
- * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
- * which group key cipher will be used with the connection (a u32).
- * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
- * which WPA version(s) the AP we want to associate with is using
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ * indicate which group key cipher will be used with the connection (a
+ * u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ * indicate which WPA version(s) the AP we want to associate with is using
* (a u32 with flags from &enum nl80211_wpa_versions).
- * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
- * which key management algorithm(s) to use (an array of u32).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ * indicate which key management algorithm(s) to use (an array of u32).
*
* @NL80211_ATTR_REQ_IE: (Re)association request information elements as
* sent out by the card, for ROAM and successful CONNECT events.
@@ -852,7 +1024,13 @@ enum nl80211_commands {
* This can be used to mask out antennas which are not attached or should
* not be used for receiving. If an antenna is not selected in this bitmap
* the hardware should not be configured to receive on this antenna.
- * For a more detailed descripton see @NL80211_ATTR_WIPHY_ANTENNA_TX.
+ * For a more detailed description see @NL80211_ATTR_WIPHY_ANTENNA_TX.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX: Bitmap of antennas which are available
+ * for configuration as TX antennas via the above parameters.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: Bitmap of antennas which are available
+ * for configuration as RX antennas via the above parameters.
*
* @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS
*
@@ -868,11 +1046,135 @@ enum nl80211_commands {
* attributes, specifying what a key should be set as default as.
* See &enum nl80211_key_default_types.
*
+ * @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters. These cannot be
+ * changed once the mesh is active.
+ * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute
+ * containing attributes from &enum nl80211_meshconf_params.
+ * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver
+ * allows auth frames in a mesh to be passed to userspace for processing via
+ * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
+ * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as
+ * defined in &enum nl80211_plink_state. Used when userspace is
+ * driving the peer link management state machine.
+ * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled.
+ *
+ * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy
+ * capabilities, the supported WoWLAN triggers
+ * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to
+ * indicate which WoW triggers should be enabled. This is also
+ * used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN
+ * triggers.
+
+ * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
+ * cycles, in msecs.
+
+ * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
+ * sets of attributes to match during scheduled scans. Only BSSs
+ * that match any of the sets will be reported. These are
+ * pass-thru filter rules.
+ * For a match to succeed, the BSS must match all attributes of a
+ * set. Since not every hardware supports matching all types of
+ * attributes, there is no guarantee that the reported BSSs are
+ * fully complying with the match sets and userspace needs to be
+ * able to ignore them by itself.
+ * Thus, the implementation is somewhat hardware-dependent, but
+ * this is only an optimization and the userspace application
+ * needs to handle all the non-filtered results anyway.
+ * If the match attributes don't make sense when combined with
+ * the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID
+ * is included in the probe request, but the match attributes
+ * will never let it go through), -EINVAL may be returned.
+ * If ommited, no filtering is done.
+ *
+ * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
+ * interface combinations. In each nested item, it contains attributes
+ * defined in &enum nl80211_if_combination_attrs.
+ * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like
+ * %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that
+ * are managed in software: interfaces of these types aren't subject to
+ * any restrictions in their number or combinations.
+ *
+ * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ * necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
+ *
+ * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan,
+ * nested array attribute containing an entry for each band, with the entry
+ * being a list of supported rates as defined by IEEE 802.11 7.3.2.2 but
+ * without the length restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon
+ * and Probe Response (when response to wildcard Probe Request); see
+ * &enum nl80211_hidden_ssid, represented as a u32
+ *
+ * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame.
+ * This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to
+ * provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the
+ * driver (or firmware) replies to Probe Request frames.
+ * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association
+ * Response frames. This is used with %NL80211_CMD_NEW_BEACON and
+ * %NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
+ * (Re)Association Response frames when the driver (or firmware) replies to
+ * (Re)Association Request frames.
+ *
+ * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
+ * of the station, see &enum nl80211_sta_wme_attr.
+ * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working
+ * as AP.
+ *
+ * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of
+ * roaming to another AP in the same ESS if the signal lever is low.
+ *
+ * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
+ * candidate information, see &enum nl80211_pmksa_candidate_attr.
+ *
+ * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
+ * for management frames transmission. In order to avoid p2p probe/action
+ * frames are being transmitted at CCK rate in 2GHz band, the user space
+ * applications use this attribute.
+ * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
+ * %NL80211_CMD_FRAME commands.
+ *
+ * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
+ * request, link setup confirm, link teardown, etc.). Values are
+ * described in the TDLS (802.11z) specification.
+ * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
+ * TDLS conversation between two devices.
+ * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
+ * &enum nl80211_tdls_operation, represented as a u8.
+ * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
+ * as a TDLS peer sta.
+ * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
+ * procedures should be performed by sending TDLS packets via
+ * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
+ * used for asking the driver to perform a TDLS operation.
+ *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ * that have AP support to indicate that they have the AP SME integrated
+ * with support for the features listed in this attribute, see
+ * &enum nl80211_ap_sme_features.
+ *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ * the driver to not wait for an acknowledgement. Note that due to this,
+ * it will also not give a status callback nor return a cookie. This is
+ * mostly useful for probe responses to save airtime.
+ *
+ * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
+ * &enum nl80211_feature_flags and is advertised in wiphy information.
+ * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
+ *
+ * requests while operating in AP-mode.
+ * This attribute holds a bitmap of the supported protocols for
+ * offloading (see &enum nl80211_probe_resp_offload_support_attr).
+ *
+ * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
+ * probe-response frame. The DA field in the 802.11 header is zero-ed out,
+ * to be filled by the FW.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
enum nl80211_attrs {
-/* don't change the order or add anything inbetween, this is ABI! */
+/* don't change the order or add anything between, this is ABI! */
NL80211_ATTR_UNSPEC,
NL80211_ATTR_WIPHY,
@@ -922,7 +1224,7 @@ enum nl80211_attrs {
NL80211_ATTR_REG_ALPHA2,
NL80211_ATTR_REG_RULES,
- NL80211_ATTR_MESH_PARAMS,
+ NL80211_ATTR_MESH_CONFIG,
NL80211_ATTR_BSS_BASIC_RATES,
@@ -1050,6 +1352,62 @@ enum nl80211_attrs {
NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
+ NL80211_ATTR_MESH_SETUP,
+
+ NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
+ NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
+
+ NL80211_ATTR_SUPPORT_MESH_AUTH,
+ NL80211_ATTR_STA_PLINK_STATE,
+
+ NL80211_ATTR_WOWLAN_TRIGGERS,
+ NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED,
+
+ NL80211_ATTR_SCHED_SCAN_INTERVAL,
+
+ NL80211_ATTR_INTERFACE_COMBINATIONS,
+ NL80211_ATTR_SOFTWARE_IFTYPES,
+
+ NL80211_ATTR_REKEY_DATA,
+
+ NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+ NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
+
+ NL80211_ATTR_SCAN_SUPP_RATES,
+
+ NL80211_ATTR_HIDDEN_SSID,
+
+ NL80211_ATTR_IE_PROBE_RESP,
+ NL80211_ATTR_IE_ASSOC_RESP,
+
+ NL80211_ATTR_STA_WME,
+ NL80211_ATTR_SUPPORT_AP_UAPSD,
+
+ NL80211_ATTR_ROAM_SUPPORT,
+
+ NL80211_ATTR_SCHED_SCAN_MATCH,
+ NL80211_ATTR_MAX_MATCH_SETS,
+
+ NL80211_ATTR_PMKSA_CANDIDATE,
+
+ NL80211_ATTR_TX_NO_CCK_RATE,
+
+ NL80211_ATTR_TDLS_ACTION,
+ NL80211_ATTR_TDLS_DIALOG_TOKEN,
+ NL80211_ATTR_TDLS_OPERATION,
+ NL80211_ATTR_TDLS_SUPPORT,
+ NL80211_ATTR_TDLS_EXTERNAL_SETUP,
+
+ NL80211_ATTR_DEVICE_AP_SME,
+
+ NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
+ NL80211_ATTR_FEATURE_FLAGS,
+
+ NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
+ NL80211_ATTR_PROBE_RESP,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1058,6 +1416,7 @@ enum nl80211_attrs {
/* source-level API compatibility */
#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
+#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
/*
* Allow user space programs to use #ifdef on new attributes by defining them
@@ -1083,6 +1442,7 @@ enum nl80211_attrs {
#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
#define NL80211_ATTR_KEY NL80211_ATTR_KEY
#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_REG_RULES 32
@@ -1101,7 +1461,9 @@ enum nl80211_attrs {
* @NL80211_IFTYPE_ADHOC: independent BSS member
* @NL80211_IFTYPE_STATION: managed BSS member
* @NL80211_IFTYPE_AP: access point
- * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces
+ * are a bit special in that they must always be tied to a pre-existing
+ * AP type interface.
* @NL80211_IFTYPE_WDS: wireless distribution interface
* @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
* @NL80211_IFTYPE_MESH_POINT: mesh point
@@ -1143,6 +1505,8 @@ enum nl80211_iftype {
* with short barker preamble
* @NL80211_STA_FLAG_WME: station is WME/QoS capable
* @NL80211_STA_FLAG_MFP: station uses management frame protection
+ * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
+ * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined
* @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
@@ -1152,6 +1516,8 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_SHORT_PREAMBLE,
NL80211_STA_FLAG_WME,
NL80211_STA_FLAG_MFP,
+ NL80211_STA_FLAG_AUTHENTICATED,
+ NL80211_STA_FLAG_TDLS_PEER,
/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
@@ -1197,6 +1563,36 @@ enum nl80211_rate_info {
};
/**
+ * enum nl80211_sta_bss_param - BSS information collected by STA
+ *
+ * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE: whether short preamble is enabled
+ * (flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME: whether short slot time is enabled
+ * (flag)
+ * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8)
+ * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16)
+ * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined
+ * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use
+ */
+enum nl80211_sta_bss_param {
+ __NL80211_STA_BSS_PARAM_INVALID,
+ NL80211_STA_BSS_PARAM_CTS_PROT,
+ NL80211_STA_BSS_PARAM_SHORT_PREAMBLE,
+ NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME,
+ NL80211_STA_BSS_PARAM_DTIM_PERIOD,
+ NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
+
+ /* keep last */
+ __NL80211_STA_BSS_PARAM_AFTER_LAST,
+ NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_sta_info - station information
*
* These attribute types are used with %NL80211_ATTR_STA_INFO
@@ -1206,17 +1602,27 @@ enum nl80211_rate_info {
* @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
* @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
* @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
- * @__NL80211_STA_INFO_AFTER_LAST: internal
- * @NL80211_STA_INFO_MAX: highest possible station info attribute
* @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
* @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
- * containing info as possible, see &enum nl80211_sta_info_txrate.
+ * containing info as possible, see &enum nl80211_rate_info
* @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
* @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
* station)
* @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
* @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
* @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
+ * @NL80211_STA_INFO_LLID: the station's mesh LLID
+ * @NL80211_STA_INFO_PLID: the station's mesh PLID
+ * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
+ * (see %enum nl80211_plink_state)
+ * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested
+ * attribute, like NL80211_STA_INFO_TX_BITRATE.
+ * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute
+ * containing info as possible, see &enum nl80211_sta_bss_param
+ * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected
+ * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
enum nl80211_sta_info {
__NL80211_STA_INFO_INVALID,
@@ -1233,6 +1639,10 @@ enum nl80211_sta_info {
NL80211_STA_INFO_TX_RETRIES,
NL80211_STA_INFO_TX_FAILED,
NL80211_STA_INFO_SIGNAL_AVG,
+ NL80211_STA_INFO_RX_BITRATE,
+ NL80211_STA_INFO_BSS_PARAM,
+ NL80211_STA_INFO_CONNECTED_TIME,
+ NL80211_STA_INFO_STA_FLAGS,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -1388,7 +1798,7 @@ enum nl80211_bitrate_attr {
* 802.11 country information element with regulatory information it
* thinks we should consider. cfg80211 only processes the country
* code from the IE, and relies on the regulatory domain information
- * structure pased by userspace (CRDA) from our wireless-regdb.
+ * structure passed by userspace (CRDA) from our wireless-regdb.
* If a channel is enabled but the country code indicates it should
* be disabled we disable the channel and re-enable it upon disassociation.
*/
@@ -1462,6 +1872,26 @@ enum nl80211_reg_rule_attr {
};
/**
+ * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
+ * only report BSS with matching SSID.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
+ * attribute number currently defined
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_sched_scan_match_attr {
+ __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
+
+ NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+
+ /* keep last */
+ __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
+ NL80211_SCHED_SCAN_MATCH_ATTR_MAX =
+ __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_reg_rule_flags - regulatory rule flags
*
* @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
@@ -1559,14 +1989,15 @@ enum nl80211_mntr_flags {
/**
* enum nl80211_meshconf_params - mesh configuration parameters
*
- * Mesh configuration parameters
+ * Mesh configuration parameters. These can be changed while the mesh is
+ * active.
*
* @__NL80211_MESHCONF_INVALID: internal use
*
* @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
* millisecond units, used by the Peer Link Open message
*
- * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in
+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in
* millisecond units, used by the peer link management to close a peer link
*
* @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
@@ -1582,9 +2013,6 @@ enum nl80211_mntr_flags {
* @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
* point.
*
- * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
- * source mesh point for path selection elements.
- *
* @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
* open peer links when we detect compatible mesh peers.
*
@@ -1609,7 +2037,17 @@ enum nl80211_mntr_flags {
* @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
* that it takes for an HWMP information element to propagate across the mesh
*
- * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
+ * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not
+ *
+ * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
+ * source mesh point for path selection elements.
+ *
+ * @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between
+ * root announcements are transmitted.
+ *
+ * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
+ * access to a broader network beyond the MBSS. This is done via Root
+ * Announcement frames.
*
* @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
*
@@ -1632,6 +2070,8 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
NL80211_MESHCONF_HWMP_ROOTMODE,
NL80211_MESHCONF_ELEMENT_TTL,
+ NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -1639,6 +2079,54 @@ enum nl80211_meshconf_params {
};
/**
+ * enum nl80211_mesh_setup_params - mesh setup parameters
+ *
+ * Mesh setup parameters. These are used to start/join a mesh and cannot be
+ * changed while the mesh is active.
+ *
+ * @__NL80211_MESH_SETUP_INVALID: Internal use
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a
+ * vendor specific path selection algorithm or disable it to use the default
+ * HWMP.
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a
+ * vendor specific path metric or disable it to use the default Airtime
+ * metric.
+ *
+ * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
+ * robust security network ie, or a vendor specific information element that
+ * vendors will use to identify the path selection methods and metrics in use.
+ *
+ * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication
+ * daemon will be authenticating mesh candidates.
+ *
+ * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication
+ * daemon will be securing peer link frames. AMPE is a secured version of Mesh
+ * Peering Management (MPM) and is implemented with the assistance of a
+ * userspace daemon. When this flag is set, the kernel will send peer
+ * management frames to a userspace daemon that will implement AMPE
+ * functionality (security capabilities selection, key confirmation, and key
+ * management). When the flag is unset (default), the kernel can autonomously
+ * complete (unsecured) mesh peering without the need of a userspace daemon.
+ *
+ * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
+ * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
+ */
+enum nl80211_mesh_setup_params {
+ __NL80211_MESH_SETUP_INVALID,
+ NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL,
+ NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC,
+ NL80211_MESH_SETUP_IE,
+ NL80211_MESH_SETUP_USERSPACE_AUTH,
+ NL80211_MESH_SETUP_USERSPACE_AMPE,
+
+ /* keep last */
+ __NL80211_MESH_SETUP_ATTR_AFTER_LAST,
+ NL80211_MESH_SETUP_ATTR_MAX = __NL80211_MESH_SETUP_ATTR_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_txq_attr - TX queue parameter attributes
* @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
* @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
@@ -1936,4 +2424,341 @@ enum nl80211_tx_power_setting {
NL80211_TX_POWER_FIXED,
};
+/**
+ * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
+ * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
+ * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
+ * a zero bit are ignored
+ * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have
+ * a bit for each byte in the pattern. The lowest-order bit corresponds
+ * to the first byte of the pattern, but the bytes of the pattern are
+ * in a little-endian-like format, i.e. the 9th byte of the pattern
+ * corresponds to the lowest-order bit in the second byte of the mask.
+ * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where
+ * xx indicates "don't care") would be represented by a pattern of
+ * twelve zero bytes, and a mask of "0xed,0x07".
+ * Note that the pattern matching is done as though frames were not
+ * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
+ * first (including SNAP header unpacking) and then matched.
+ * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
+ * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
+ */
+enum nl80211_wowlan_packet_pattern_attr {
+ __NL80211_WOWLAN_PKTPAT_INVALID,
+ NL80211_WOWLAN_PKTPAT_MASK,
+ NL80211_WOWLAN_PKTPAT_PATTERN,
+
+ NUM_NL80211_WOWLAN_PKTPAT,
+ MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
+};
+
+/**
+ * struct nl80211_wowlan_pattern_support - pattern support information
+ * @max_patterns: maximum number of patterns supported
+ * @min_pattern_len: minimum length of each pattern
+ * @max_pattern_len: maximum length of each pattern
+ *
+ * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
+ * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
+ * capability information given by the kernel to userspace.
+ */
+struct nl80211_wowlan_pattern_support {
+ __u32 max_patterns;
+ __u32 min_pattern_len;
+ __u32 max_pattern_len;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
+ * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
+ * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
+ * the chip into a special state -- works best with chips that have
+ * support for low-power operation already (flag)
+ * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
+ * is detected is implementation-specific (flag)
+ * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
+ * by 16 repetitions of MAC addr, anywhere in payload) (flag)
+ * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns
+ * which are passed in an array of nested attributes, each nested attribute
+ * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern.
+ * Each pattern defines a wakeup packet. The matching is done on the MSDU,
+ * i.e. as though the packet was an 802.3 packet, so the pattern matching
+ * is done after the packet is converted to the MSDU.
+ *
+ * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
+ * carrying a &struct nl80211_wowlan_pattern_support.
+ * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be
+ * used when setting, used only to indicate that GTK rekeying is supported
+ * by the device (flag)
+ * @NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE: wake up on GTK rekey failure (if
+ * done by the device) (flag)
+ * @NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST: wake up on EAP Identity Request
+ * packet (flag)
+ * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag)
+ * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released
+ * (on devices that have rfkill in the device) (flag)
+ * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
+ * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
+ */
+enum nl80211_wowlan_triggers {
+ __NL80211_WOWLAN_TRIG_INVALID,
+ NL80211_WOWLAN_TRIG_ANY,
+ NL80211_WOWLAN_TRIG_DISCONNECT,
+ NL80211_WOWLAN_TRIG_MAGIC_PKT,
+ NL80211_WOWLAN_TRIG_PKT_PATTERN,
+ NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED,
+ NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE,
+ NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST,
+ NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE,
+ NL80211_WOWLAN_TRIG_RFKILL_RELEASE,
+
+ /* keep last */
+ NUM_NL80211_WOWLAN_TRIG,
+ MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1
+};
+
+/**
+ * enum nl80211_iface_limit_attrs - limit attributes
+ * @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
+ * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
+ * can be chosen from this set of interface types (u32)
+ * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a
+ * flag attribute for each interface type in this set
+ * @NUM_NL80211_IFACE_LIMIT: number of attributes
+ * @MAX_NL80211_IFACE_LIMIT: highest attribute number
+ */
+enum nl80211_iface_limit_attrs {
+ NL80211_IFACE_LIMIT_UNSPEC,
+ NL80211_IFACE_LIMIT_MAX,
+ NL80211_IFACE_LIMIT_TYPES,
+
+ /* keep last */
+ NUM_NL80211_IFACE_LIMIT,
+ MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1
+};
+
+/**
+ * enum nl80211_if_combination_attrs -- interface combination attributes
+ *
+ * @NL80211_IFACE_COMB_UNSPEC: (reserved)
+ * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits
+ * for given interface types, see &enum nl80211_iface_limit_attrs.
+ * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of
+ * interfaces that can be created in this group. This number doesn't
+ * apply to interfaces purely managed in software, which are listed
+ * in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE.
+ * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that
+ * beacon intervals within this group must be all the same even for
+ * infrastructure and AP/GO combinations, i.e. the GO(s) must adopt
+ * the infrastructure network's beacon interval.
+ * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many
+ * different channels may be used within this group.
+ * @NUM_NL80211_IFACE_COMB: number of attributes
+ * @MAX_NL80211_IFACE_COMB: highest attribute number
+ *
+ * Examples:
+ * limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
+ * => allows an AP and a STA that must match BIs
+ *
+ * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8
+ * => allows 8 of AP/GO
+ *
+ * numbers = [ #{STA} <= 2 ], channels = 2, max = 2
+ * => allows two STAs on different channels
+ *
+ * numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4
+ * => allows a STA plus three P2P interfaces
+ *
+ * The list of these four possiblities could completely be contained
+ * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate
+ * that any of these groups must match.
+ *
+ * "Combinations" of just a single interface will not be listed here,
+ * a single interface of any valid interface type is assumed to always
+ * be possible by itself. This means that implicitly, for each valid
+ * interface type, the following group always exists:
+ * numbers = [ #{<type>} <= 1 ], channels = 1, max = 1
+ */
+enum nl80211_if_combination_attrs {
+ NL80211_IFACE_COMB_UNSPEC,
+ NL80211_IFACE_COMB_LIMITS,
+ NL80211_IFACE_COMB_MAXNUM,
+ NL80211_IFACE_COMB_STA_AP_BI_MATCH,
+ NL80211_IFACE_COMB_NUM_CHANNELS,
+
+ /* keep last */
+ NUM_NL80211_IFACE_COMB,
+ MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1
+};
+
+
+/**
+ * enum nl80211_plink_state - state of a mesh peer link finite state machine
+ *
+ * @NL80211_PLINK_LISTEN: initial state, considered the implicit
+ * state of non existant mesh peer links
+ * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to
+ * this mesh peer
+ * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received
+ * from this mesh peer
+ * @NL80211_PLINK_CNF_RCVD: mesh plink confirm frame has been
+ * received from this mesh peer
+ * @NL80211_PLINK_ESTAB: mesh peer link is established
+ * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled
+ * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh
+ * plink are discarded
+ * @NUM_NL80211_PLINK_STATES: number of peer link states
+ * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states
+ */
+enum nl80211_plink_state {
+ NL80211_PLINK_LISTEN,
+ NL80211_PLINK_OPN_SNT,
+ NL80211_PLINK_OPN_RCVD,
+ NL80211_PLINK_CNF_RCVD,
+ NL80211_PLINK_ESTAB,
+ NL80211_PLINK_HOLDING,
+ NL80211_PLINK_BLOCKED,
+
+ /* keep last */
+ NUM_NL80211_PLINK_STATES,
+ MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
+};
+
+#define NL80211_KCK_LEN 16
+#define NL80211_KEK_LEN 16
+#define NL80211_REPLAY_CTR_LEN 8
+
+/**
+ * enum nl80211_rekey_data - attributes for GTK rekey offload
+ * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes
+ * @NL80211_REKEY_DATA_KEK: key encryption key (binary)
+ * @NL80211_REKEY_DATA_KCK: key confirmation key (binary)
+ * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary)
+ * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal)
+ * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal)
+ */
+enum nl80211_rekey_data {
+ __NL80211_REKEY_DATA_INVALID,
+ NL80211_REKEY_DATA_KEK,
+ NL80211_REKEY_DATA_KCK,
+ NL80211_REKEY_DATA_REPLAY_CTR,
+
+ /* keep last */
+ NUM_NL80211_REKEY_DATA,
+ MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1
+};
+
+/**
+ * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID
+ * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in
+ * Beacon frames)
+ * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element
+ * in Beacon frames
+ * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID
+ * element in Beacon frames but zero out each byte in the SSID
+ */
+enum nl80211_hidden_ssid {
+ NL80211_HIDDEN_SSID_NOT_IN_USE,
+ NL80211_HIDDEN_SSID_ZERO_LEN,
+ NL80211_HIDDEN_SSID_ZERO_CONTENTS
+};
+
+/**
+ * enum nl80211_sta_wme_attr - station WME attributes
+ * @__NL80211_STA_WME_INVALID: invalid number for nested attribute
+ * @NL80211_STA_WME_UAPSD_QUEUES: bitmap of uapsd queues. the format
+ * is the same as the AC bitmap in the QoS info field.
+ * @NL80211_STA_WME_MAX_SP: max service period. the format is the same
+ * as the MAX_SP field in the QoS info field (but already shifted down).
+ * @__NL80211_STA_WME_AFTER_LAST: internal
+ * @NL80211_STA_WME_MAX: highest station WME attribute
+ */
+enum nl80211_sta_wme_attr {
+ __NL80211_STA_WME_INVALID,
+ NL80211_STA_WME_UAPSD_QUEUES,
+ NL80211_STA_WME_MAX_SP,
+
+ /* keep last */
+ __NL80211_STA_WME_AFTER_LAST,
+ NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_pmksa_candidate_attr - attributes for PMKSA caching candidates
+ * @__NL80211_PMKSA_CANDIDATE_INVALID: invalid number for nested attributes
+ * @NL80211_PMKSA_CANDIDATE_INDEX: candidate index (u32; the smaller, the higher
+ * priority)
+ * @NL80211_PMKSA_CANDIDATE_BSSID: candidate BSSID (6 octets)
+ * @NL80211_PMKSA_CANDIDATE_PREAUTH: RSN pre-authentication supported (flag)
+ * @NUM_NL80211_PMKSA_CANDIDATE: number of PMKSA caching candidate attributes
+ * (internal)
+ * @MAX_NL80211_PMKSA_CANDIDATE: highest PMKSA caching candidate attribute
+ * (internal)
+ */
+enum nl80211_pmksa_candidate_attr {
+ __NL80211_PMKSA_CANDIDATE_INVALID,
+ NL80211_PMKSA_CANDIDATE_INDEX,
+ NL80211_PMKSA_CANDIDATE_BSSID,
+ NL80211_PMKSA_CANDIDATE_PREAUTH,
+
+ /* keep last */
+ NUM_NL80211_PMKSA_CANDIDATE,
+ MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1
+};
+
+/**
+ * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION
+ * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request
+ * @NL80211_TDLS_SETUP: Setup TDLS link
+ * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established
+ * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link
+ * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link
+ */
+enum nl80211_tdls_operation {
+ NL80211_TDLS_DISCOVERY_REQ,
+ NL80211_TDLS_SETUP,
+ NL80211_TDLS_TEARDOWN,
+ NL80211_TDLS_ENABLE_LINK,
+ NL80211_TDLS_DISABLE_LINK,
+};
+
+/*
+ * enum nl80211_ap_sme_features - device-integrated AP features
+ * Reserved for future use, no bits are defined in
+ * NL80211_ATTR_DEVICE_AP_SME yet.
+enum nl80211_ap_sme_features {
+};
+ */
+
+/**
+ * enum nl80211_feature_flags - device/driver features
+ * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back
+ * TX status to the socket error queue when requested with the
+ * socket option.
+ */
+enum nl80211_feature_flags {
+ NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
+};
+
+/**
+ * enum nl80211_probe_resp_offload_support_attr - optional supported
+ * protocols for probe-response offloading by the driver/FW.
+ * To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
+ * Each enum value represents a bit in the bitmap of supported
+ * protocols. Typically a subset of probe-requests belonging to a
+ * supported protocol will be excluded from offload and uploaded
+ * to the host.
+ *
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u
+ */
+enum nl80211_probe_resp_offload_support_attr {
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS = 1<<0,
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 = 1<<1,
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P = 1<<2,
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/drivers/wireless_copy.h b/src/drivers/wireless_copy.h
deleted file mode 100644
index 201719b..0000000
--- a/src/drivers/wireless_copy.h
+++ /dev/null
@@ -1,1185 +0,0 @@
-/* This is based on Linux Wireless Extensions header file from WIRELESS_EXT 22.
- * I have just removed kernel related headers and added some typedefs etc. to
- * make this easier to include into user space programs.
- * Jouni Malinen, 2005-03-12.
- */
-
-
-/*
- * This file define a set of standard wireless extensions
- *
- * Version : 22 16.3.07
- *
- * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
- */
-
-#ifndef _LINUX_WIRELESS_H
-#define _LINUX_WIRELESS_H
-
-/************************** DOCUMENTATION **************************/
-/*
- * Initial APIs (1996 -> onward) :
- * -----------------------------
- * Basically, the wireless extensions are for now a set of standard ioctl
- * call + /proc/net/wireless
- *
- * The entry /proc/net/wireless give statistics and information on the
- * driver.
- * This is better than having each driver having its entry because
- * its centralised and we may remove the driver module safely.
- *
- * Ioctl are used to configure the driver and issue commands. This is
- * better than command line options of insmod because we may want to
- * change dynamically (while the driver is running) some parameters.
- *
- * The ioctl mechanimsm are copied from standard devices ioctl.
- * We have the list of command plus a structure descibing the
- * data exchanged...
- * Note that to add these ioctl, I was obliged to modify :
- * # net/core/dev.c (two place + add include)
- * # net/ipv4/af_inet.c (one place + add include)
- *
- * /proc/net/wireless is a copy of /proc/net/dev.
- * We have a structure for data passed from the driver to /proc/net/wireless
- * Too add this, I've modified :
- * # net/core/dev.c (two other places)
- * # include/linux/netdevice.h (one place)
- * # include/linux/proc_fs.h (one place)
- *
- * New driver API (2002 -> onward) :
- * -------------------------------
- * This file is only concerned with the user space API and common definitions.
- * The new driver API is defined and documented in :
- * # include/net/iw_handler.h
- *
- * Note as well that /proc/net/wireless implementation has now moved in :
- * # net/core/wireless.c
- *
- * Wireless Events (2002 -> onward) :
- * --------------------------------
- * Events are defined at the end of this file, and implemented in :
- * # net/core/wireless.c
- *
- * Other comments :
- * --------------
- * Do not add here things that are redundant with other mechanisms
- * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
- * wireless specific.
- *
- * These wireless extensions are not magic : each driver has to provide
- * support for them...
- *
- * IMPORTANT NOTE : As everything in the kernel, this is very much a
- * work in progress. Contact me if you have ideas of improvements...
- */
-
-/***************************** INCLUDES *****************************/
-
- /* jkm - replaced linux headers with C library headers, added typedefs */
-#if 0
-#include <linux/types.h> /* for __u* and __s* typedefs */
-#include <linux/socket.h> /* for "struct sockaddr" et al */
-#include <linux/if.h> /* for IFNAMSIZ and co... */
-#else
-#include <sys/types.h>
-#include <net/if.h>
-#ifndef ANDROID
-typedef __uint32_t __u32;
-typedef __int32_t __s32;
-typedef __uint16_t __u16;
-typedef __int16_t __s16;
-typedef __uint8_t __u8;
-#endif /* ANDROID */
-#ifndef __user
-#define __user
-#endif /* __user */
-#endif
-
-/***************************** VERSION *****************************/
-/*
- * This constant is used to know the availability of the wireless
- * extensions and to know which version of wireless extensions it is
- * (there is some stuff that will be added in the future...)
- * I just plan to increment with each new version.
- */
-#define WIRELESS_EXT 22
-
-/*
- * Changes :
- *
- * V2 to V3
- * --------
- * Alan Cox start some incompatibles changes. I've integrated a bit more.
- * - Encryption renamed to Encode to avoid US regulation problems
- * - Frequency changed from float to struct to avoid problems on old 386
- *
- * V3 to V4
- * --------
- * - Add sensitivity
- *
- * V4 to V5
- * --------
- * - Missing encoding definitions in range
- * - Access points stuff
- *
- * V5 to V6
- * --------
- * - 802.11 support (ESSID ioctls)
- *
- * V6 to V7
- * --------
- * - define IW_ESSID_MAX_SIZE and IW_MAX_AP
- *
- * V7 to V8
- * --------
- * - Changed my e-mail address
- * - More 802.11 support (nickname, rate, rts, frag)
- * - List index in frequencies
- *
- * V8 to V9
- * --------
- * - Support for 'mode of operation' (ad-hoc, managed...)
- * - Support for unicast and multicast power saving
- * - Change encoding to support larger tokens (>64 bits)
- * - Updated iw_params (disable, flags) and use it for NWID
- * - Extracted iw_point from iwreq for clarity
- *
- * V9 to V10
- * ---------
- * - Add PM capability to range structure
- * - Add PM modifier : MAX/MIN/RELATIVE
- * - Add encoding option : IW_ENCODE_NOKEY
- * - Add TxPower ioctls (work like TxRate)
- *
- * V10 to V11
- * ----------
- * - Add WE version in range (help backward/forward compatibility)
- * - Add retry ioctls (work like PM)
- *
- * V11 to V12
- * ----------
- * - Add SIOCSIWSTATS to get /proc/net/wireless programatically
- * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
- * - Add new statistics (frag, retry, beacon)
- * - Add average quality (for user space calibration)
- *
- * V12 to V13
- * ----------
- * - Document creation of new driver API.
- * - Extract union iwreq_data from struct iwreq (for new driver API).
- * - Rename SIOCSIWNAME as SIOCSIWCOMMIT
- *
- * V13 to V14
- * ----------
- * - Wireless Events support : define struct iw_event
- * - Define additional specific event numbers
- * - Add "addr" and "param" fields in union iwreq_data
- * - AP scanning stuff (SIOCSIWSCAN and friends)
- *
- * V14 to V15
- * ----------
- * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
- * - Make struct iw_freq signed (both m & e), add explicit padding
- * - Add IWEVCUSTOM for driver specific event/scanning token
- * - Add IW_MAX_GET_SPY for driver returning a lot of addresses
- * - Add IW_TXPOW_RANGE for range of Tx Powers
- * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
- * - Add IW_MODE_MONITOR for passive monitor
- *
- * V15 to V16
- * ----------
- * - Increase the number of bitrates in iw_range to 32 (for 802.11g)
- * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a)
- * - Reshuffle struct iw_range for increases, add filler
- * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses
- * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support
- * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
- * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index
- *
- * V16 to V17
- * ----------
- * - Add flags to frequency -> auto/fixed
- * - Document (struct iw_quality *)->updated, add new flags (INVALID)
- * - Wireless Event capability in struct iw_range
- * - Add support for relative TxPower (yick !)
- *
- * V17 to V18 (From Jouni Malinen <j@w1.fi>)
- * ----------
- * - Add support for WPA/WPA2
- * - Add extended encoding configuration (SIOCSIWENCODEEXT and
- * SIOCGIWENCODEEXT)
- * - Add SIOCSIWGENIE/SIOCGIWGENIE
- * - Add SIOCSIWMLME
- * - Add SIOCSIWPMKSA
- * - Add struct iw_range bit field for supported encoding capabilities
- * - Add optional scan request parameters for SIOCSIWSCAN
- * - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA
- * related parameters (extensible up to 4096 parameter values)
- * - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE,
- * IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND
- *
- * V18 to V19
- * ----------
- * - Remove (struct iw_point *)->pointer from events and streams
- * - Remove header includes to help user space
- * - Increase IW_ENCODING_TOKEN_MAX from 32 to 64
- * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros
- * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM
- * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros
- *
- * V19 to V20
- * ----------
- * - RtNetlink requests support (SET/GET)
- *
- * V20 to V21
- * ----------
- * - Remove (struct net_device *)->get_wireless_stats()
- * - Change length in ESSID and NICK to strlen() instead of strlen()+1
- * - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers
- * - Power/Retry relative values no longer * 100000
- * - Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI
- *
- * V21 to V22
- * ----------
- * - Prevent leaking of kernel space in stream on 64 bits.
- */
-
-/**************************** CONSTANTS ****************************/
-
-/* -------------------------- IOCTL LIST -------------------------- */
-
-/* Wireless Identification */
-#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */
-#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
-/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
- * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
- * Don't put the name of your driver there, it's useless. */
-
-/* Basic operations */
-#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */
-#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */
-#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */
-#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */
-#define SIOCSIWMODE 0x8B06 /* set operation mode */
-#define SIOCGIWMODE 0x8B07 /* get operation mode */
-#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */
-#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */
-
-/* Informative stuff */
-#define SIOCSIWRANGE 0x8B0A /* Unused */
-#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */
-#define SIOCSIWPRIV 0x8B0C /* Unused */
-#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */
-#define SIOCSIWSTATS 0x8B0E /* Unused */
-#define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */
-/* SIOCGIWSTATS is strictly used between user space and the kernel, and
- * is never passed to the driver (i.e. the driver will never see it). */
-
-/* Spy support (statistics per MAC address - used for Mobile IP support) */
-#define SIOCSIWSPY 0x8B10 /* set spy addresses */
-#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */
-#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */
-#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */
-
-/* Access Point manipulation */
-#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */
-#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */
-#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */
-#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */
-#define SIOCGIWSCAN 0x8B19 /* get scanning results */
-
-/* 802.11 specific support */
-#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */
-#define SIOCGIWESSID 0x8B1B /* get ESSID */
-#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */
-#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */
-/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
- * within the 'iwreq' structure, so we need to use the 'data' member to
- * point to a string in user space, like it is done for RANGE... */
-
-/* Other parameters useful in 802.11 and some other devices */
-#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */
-#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */
-#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */
-#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */
-#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */
-#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */
-#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */
-#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */
-#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */
-#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */
-
-/* Encoding stuff (scrambling, hardware security, WEP...) */
-#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */
-#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */
-/* Power saving stuff (power management, unicast and multicast) */
-#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */
-#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */
-
-/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM).
- * This ioctl uses struct iw_point and data buffer that includes IE id and len
- * fields. More than one IE may be included in the request. Setting the generic
- * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers
- * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers
- * are required to report the used IE as a wireless event, e.g., when
- * associating with an AP. */
-#define SIOCSIWGENIE 0x8B30 /* set generic IE */
-#define SIOCGIWGENIE 0x8B31 /* get generic IE */
-
-/* WPA : IEEE 802.11 MLME requests */
-#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses
- * struct iw_mlme */
-/* WPA : Authentication mode parameters */
-#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */
-#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */
-
-/* WPA : Extended version of encoding configuration */
-#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */
-#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */
-
-/* WPA2 : PMKSA cache management */
-#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */
-
-/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
-
-/* These 32 ioctl are wireless device private, for 16 commands.
- * Each driver is free to use them for whatever purpose it chooses,
- * however the driver *must* export the description of those ioctls
- * with SIOCGIWPRIV and *must* use arguments as defined below.
- * If you don't follow those rules, DaveM is going to hate you (reason :
- * it make mixed 32/64bit operation impossible).
- */
-#define SIOCIWFIRSTPRIV 0x8BE0
-#define SIOCIWLASTPRIV 0x8BFF
-/* Previously, we were using SIOCDEVPRIVATE, but we now have our
- * separate range because of collisions with other tools such as
- * 'mii-tool'.
- * We now have 32 commands, so a bit more space ;-).
- * Also, all 'even' commands are only usable by root and don't return the
- * content of ifr/iwr to user (but you are not obliged to use the set/get
- * convention, just use every other two command). More details in iwpriv.c.
- * And I repeat : you are not forced to use them with iwpriv, but you
- * must be compliant with it.
- */
-
-/* ------------------------- IOCTL STUFF ------------------------- */
-
-/* The first and the last (range) */
-#define SIOCIWFIRST 0x8B00
-#define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */
-#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST)
-#define IW_HANDLER(id, func) \
- [IW_IOCTL_IDX(id)] = func
-
-/* Odd : get (world access), even : set (root access) */
-#define IW_IS_SET(cmd) (!((cmd) & 0x1))
-#define IW_IS_GET(cmd) ((cmd) & 0x1)
-
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/* Those are *NOT* ioctls, do not issue request on them !!! */
-/* Most events use the same identifier as ioctl requests */
-
-#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */
-#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */
-#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */
-#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */
-#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */
-#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..)
- * (scan results); This includes id and
- * length fields. One IWEVGENIE may
- * contain more than one IE. Scan
- * results may contain one or more
- * IWEVGENIE events. */
-#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure
- * (struct iw_michaelmicfailure)
- */
-#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request.
- * The data includes id and length
- * fields and may contain more than one
- * IE. This event is required in
- * Managed mode if the driver
- * generates its own WPA/RSN IE. This
- * should be sent just before
- * IWEVREGISTERED event for the
- * association. */
-#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association
- * Response. The data includes id and
- * length fields and may contain more
- * than one IE. This may be sent
- * between IWEVASSOCREQIE and
- * IWEVREGISTERED events for the
- * association. */
-#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN
- * pre-authentication
- * (struct iw_pmkid_cand) */
-
-#define IWEVFIRST 0x8C00
-#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST)
-
-/* ------------------------- PRIVATE INFO ------------------------- */
-/*
- * The following is used with SIOCGIWPRIV. It allow a driver to define
- * the interface (name, type of data) for its private ioctl.
- * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV
- */
-
-#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */
-#define IW_PRIV_TYPE_NONE 0x0000
-#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */
-#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */
-#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */
-#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */
-#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */
-
-#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */
-
-#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */
-
-/*
- * Note : if the number of args is fixed and the size < 16 octets,
- * instead of passing a pointer we will put args in the iwreq struct...
- */
-
-/* ----------------------- OTHER CONSTANTS ----------------------- */
-
-/* Maximum frequencies in the range struct */
-#define IW_MAX_FREQUENCIES 32
-/* Note : if you have something like 80 frequencies,
- * don't increase this constant and don't fill the frequency list.
- * The user will be able to set by channel anyway... */
-
-/* Maximum bit rates in the range struct */
-#define IW_MAX_BITRATES 32
-
-/* Maximum tx powers in the range struct */
-#define IW_MAX_TXPOWER 8
-/* Note : if you more than 8 TXPowers, just set the max and min or
- * a few of them in the struct iw_range. */
-
-/* Maximum of address that you may set with SPY */
-#define IW_MAX_SPY 8
-
-/* Maximum of address that you may get in the
- list of access points in range */
-#define IW_MAX_AP 64
-
-/* Maximum size of the ESSID and NICKN strings */
-#define IW_ESSID_MAX_SIZE 32
-
-/* Modes of operation */
-#define IW_MODE_AUTO 0 /* Let the driver decides */
-#define IW_MODE_ADHOC 1 /* Single cell network */
-#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */
-#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */
-#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */
-#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */
-#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */
-#define IW_MODE_MESH 7 /* Mesh (IEEE 802.11s) network */
-
-/* Statistics flags (bitmask in updated) */
-#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */
-#define IW_QUAL_LEVEL_UPDATED 0x02
-#define IW_QUAL_NOISE_UPDATED 0x04
-#define IW_QUAL_ALL_UPDATED 0x07
-#define IW_QUAL_DBM 0x08 /* Level + Noise are dBm */
-#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */
-#define IW_QUAL_LEVEL_INVALID 0x20
-#define IW_QUAL_NOISE_INVALID 0x40
-#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */
-#define IW_QUAL_ALL_INVALID 0x70
-
-/* Frequency flags */
-#define IW_FREQ_AUTO 0x00 /* Let the driver decides */
-#define IW_FREQ_FIXED 0x01 /* Force a specific value */
-
-/* Maximum number of size of encoding token available
- * they are listed in the range structure */
-#define IW_MAX_ENCODING_SIZES 8
-
-/* Maximum size of the encoding token in bytes */
-#define IW_ENCODING_TOKEN_MAX 64 /* 512 bits (for now) */
-
-/* Flags for encoding (along with the token) */
-#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */
-#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */
-#define IW_ENCODE_MODE 0xF000 /* Modes defined below */
-#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */
-#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */
-#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */
-#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */
-#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */
-#define IW_ENCODE_TEMP 0x0400 /* Temporary key */
-
-/* Power management flags available (along with the value, if any) */
-#define IW_POWER_ON 0x0000 /* No details... */
-#define IW_POWER_TYPE 0xF000 /* Type of parameter */
-#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */
-#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */
-#define IW_POWER_MODE 0x0F00 /* Power Management mode */
-#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */
-#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */
-#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */
-#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */
-#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */
-#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */
-#define IW_POWER_MIN 0x0001 /* Value is a minimum */
-#define IW_POWER_MAX 0x0002 /* Value is a maximum */
-#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */
-
-/* Transmit Power flags available */
-#define IW_TXPOW_TYPE 0x00FF /* Type of value */
-#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */
-#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */
-#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */
-#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */
-
-/* Retry limits and lifetime flags available */
-#define IW_RETRY_ON 0x0000 /* No details... */
-#define IW_RETRY_TYPE 0xF000 /* Type of parameter */
-#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/
-#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */
-#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */
-#define IW_RETRY_MIN 0x0001 /* Value is a minimum */
-#define IW_RETRY_MAX 0x0002 /* Value is a maximum */
-#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */
-#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */
-#define IW_RETRY_LONG 0x0020 /* Value is for long packets */
-
-/* Scanning request flags */
-#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */
-#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */
-#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */
-#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */
-#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */
-#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */
-#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */
-#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */
-#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */
-/* struct iw_scan_req scan_type */
-#define IW_SCAN_TYPE_ACTIVE 0
-#define IW_SCAN_TYPE_PASSIVE 1
-/* Maximum size of returned data */
-#define IW_SCAN_MAX_DATA 4096 /* In bytes */
-
-/* Scan capability flags - in (struct iw_range *)->scan_capa */
-#define IW_SCAN_CAPA_NONE 0x00
-#define IW_SCAN_CAPA_ESSID 0x01
-#define IW_SCAN_CAPA_BSSID 0x02
-#define IW_SCAN_CAPA_CHANNEL 0x04
-#define IW_SCAN_CAPA_MODE 0x08
-#define IW_SCAN_CAPA_RATE 0x10
-#define IW_SCAN_CAPA_TYPE 0x20
-#define IW_SCAN_CAPA_TIME 0x40
-
-/* Max number of char in custom event - use multiple of them if needed */
-#define IW_CUSTOM_MAX 256 /* In bytes */
-
-/* Generic information element */
-#define IW_GENERIC_IE_MAX 1024
-
-/* MLME requests (SIOCSIWMLME / struct iw_mlme) */
-#define IW_MLME_DEAUTH 0
-#define IW_MLME_DISASSOC 1
-#define IW_MLME_AUTH 2
-#define IW_MLME_ASSOC 3
-
-/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */
-#define IW_AUTH_INDEX 0x0FFF
-#define IW_AUTH_FLAGS 0xF000
-/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095)
- * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the
- * parameter that is being set/get to; value will be read/written to
- * struct iw_param value field) */
-#define IW_AUTH_WPA_VERSION 0
-#define IW_AUTH_CIPHER_PAIRWISE 1
-#define IW_AUTH_CIPHER_GROUP 2
-#define IW_AUTH_KEY_MGMT 3
-#define IW_AUTH_TKIP_COUNTERMEASURES 4
-#define IW_AUTH_DROP_UNENCRYPTED 5
-#define IW_AUTH_80211_AUTH_ALG 6
-#define IW_AUTH_WPA_ENABLED 7
-#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8
-#define IW_AUTH_ROAMING_CONTROL 9
-#define IW_AUTH_PRIVACY_INVOKED 10
-#define IW_AUTH_CIPHER_GROUP_MGMT 11
-#define IW_AUTH_MFP 12
-
-/* IW_AUTH_WPA_VERSION values (bit field) */
-#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001
-#define IW_AUTH_WPA_VERSION_WPA 0x00000002
-#define IW_AUTH_WPA_VERSION_WPA2 0x00000004
-
-/* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and IW_AUTH_CIPHER_GROUP_MGMT
- * values (bit field) */
-#define IW_AUTH_CIPHER_NONE 0x00000001
-#define IW_AUTH_CIPHER_WEP40 0x00000002
-#define IW_AUTH_CIPHER_TKIP 0x00000004
-#define IW_AUTH_CIPHER_CCMP 0x00000008
-#define IW_AUTH_CIPHER_WEP104 0x00000010
-#define IW_AUTH_CIPHER_AES_CMAC 0x00000020
-
-/* IW_AUTH_KEY_MGMT values (bit field) */
-#define IW_AUTH_KEY_MGMT_802_1X 1
-#define IW_AUTH_KEY_MGMT_PSK 2
-
-/* IW_AUTH_80211_AUTH_ALG values (bit field) */
-#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001
-#define IW_AUTH_ALG_SHARED_KEY 0x00000002
-#define IW_AUTH_ALG_LEAP 0x00000004
-
-/* IW_AUTH_ROAMING_CONTROL values */
-#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */
-#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming
- * control */
-
-/* IW_AUTH_MFP (management frame protection) values */
-#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */
-#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */
-#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */
-
-/* SIOCSIWENCODEEXT definitions */
-#define IW_ENCODE_SEQ_MAX_SIZE 8
-/* struct iw_encode_ext ->alg */
-#define IW_ENCODE_ALG_NONE 0
-#define IW_ENCODE_ALG_WEP 1
-#define IW_ENCODE_ALG_TKIP 2
-#define IW_ENCODE_ALG_CCMP 3
-#define IW_ENCODE_ALG_PMK 4
-#define IW_ENCODE_ALG_AES_CMAC 5
-/* struct iw_encode_ext ->ext_flags */
-#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001
-#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002
-#define IW_ENCODE_EXT_GROUP_KEY 0x00000004
-#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008
-
-/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */
-#define IW_MICFAILURE_KEY_ID 0x00000003 /* Key ID 0..3 */
-#define IW_MICFAILURE_GROUP 0x00000004
-#define IW_MICFAILURE_PAIRWISE 0x00000008
-#define IW_MICFAILURE_STAKEY 0x00000010
-#define IW_MICFAILURE_COUNT 0x00000060 /* 1 or 2 (0 = count not supported)
- */
-
-/* Bit field values for enc_capa in struct iw_range */
-#define IW_ENC_CAPA_WPA 0x00000001
-#define IW_ENC_CAPA_WPA2 0x00000002
-#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004
-#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008
-#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010
-
-/* Event capability macros - in (struct iw_range *)->event_capa
- * Because we have more than 32 possible events, we use an array of
- * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
-#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \
- (cmd - SIOCIWFIRSTPRIV + 0x60) : \
- (cmd - SIOCIWFIRST))
-#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5)
-#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
-/* Event capability constants - event autogenerated by the kernel
- * This list is valid for most 802.11 devices, customise as needed... */
-#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \
- IW_EVENT_CAPA_MASK(0x8B06) | \
- IW_EVENT_CAPA_MASK(0x8B1A))
-#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A))
-/* "Easy" macro to set events in iw_range (less efficient) */
-#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
-#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
-
-
-/****************************** TYPES ******************************/
-
-/* --------------------------- SUBTYPES --------------------------- */
-/*
- * Generic format for most parameters that fit in an int
- */
-struct iw_param
-{
- __s32 value; /* The value of the parameter itself */
- __u8 fixed; /* Hardware should not use auto select */
- __u8 disabled; /* Disable the feature */
- __u16 flags; /* Various specifc flags (if any) */
-};
-
-/*
- * For all data larger than 16 octets, we need to use a
- * pointer to memory allocated in user space.
- */
-struct iw_point
-{
- void __user *pointer; /* Pointer to the data (in user space) */
- __u16 length; /* number of fields or size in bytes */
- __u16 flags; /* Optional params */
-};
-
-#ifdef __KERNEL__
-#ifdef CONFIG_COMPAT
-
-#include <linux/compat.h>
-
-struct compat_iw_point {
- compat_caddr_t pointer;
- __u16 length;
- __u16 flags;
-};
-#endif
-#endif
-
-/*
- * A frequency
- * For numbers lower than 10^9, we encode the number in 'm' and
- * set 'e' to 0
- * For number greater than 10^9, we divide it by the lowest power
- * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')...
- * The power of 10 is in 'e', the result of the division is in 'm'.
- */
-struct iw_freq
-{
- __s32 m; /* Mantissa */
- __s16 e; /* Exponent */
- __u8 i; /* List index (when in range struct) */
- __u8 flags; /* Flags (fixed/auto) */
-};
-
-/*
- * Quality of the link
- */
-struct iw_quality
-{
- __u8 qual; /* link quality (%retries, SNR,
- %missed beacons or better...) */
- __u8 level; /* signal level (dBm) */
- __u8 noise; /* noise level (dBm) */
- __u8 updated; /* Flags to know if updated */
-};
-
-/*
- * Packet discarded in the wireless adapter due to
- * "wireless" specific problems...
- * Note : the list of counter and statistics in net_device_stats
- * is already pretty exhaustive, and you should use that first.
- * This is only additional stats...
- */
-struct iw_discarded
-{
- __u32 nwid; /* Rx : Wrong nwid/essid */
- __u32 code; /* Rx : Unable to code/decode (WEP) */
- __u32 fragment; /* Rx : Can't perform MAC reassembly */
- __u32 retries; /* Tx : Max MAC retries num reached */
- __u32 misc; /* Others cases */
-};
-
-/*
- * Packet/Time period missed in the wireless adapter due to
- * "wireless" specific problems...
- */
-struct iw_missed
-{
- __u32 beacon; /* Missed beacons/superframe */
-};
-
-/*
- * Quality range (for spy threshold)
- */
-struct iw_thrspy
-{
- struct sockaddr addr; /* Source address (hw/mac) */
- struct iw_quality qual; /* Quality of the link */
- struct iw_quality low; /* Low threshold */
- struct iw_quality high; /* High threshold */
-};
-
-/*
- * Optional data for scan request
- *
- * Note: these optional parameters are controlling parameters for the
- * scanning behavior, these do not apply to getting scan results
- * (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and
- * provide a merged results with all BSSes even if the previous scan
- * request limited scanning to a subset, e.g., by specifying an SSID.
- * Especially, scan results are required to include an entry for the
- * current BSS if the driver is in Managed mode and associated with an AP.
- */
-struct iw_scan_req
-{
- __u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */
- __u8 essid_len;
- __u8 num_channels; /* num entries in channel_list;
- * 0 = scan all allowed channels */
- __u8 flags; /* reserved as padding; use zero, this may
- * be used in the future for adding flags
- * to request different scan behavior */
- struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or
- * individual address of a specific BSS */
-
- /*
- * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using
- * the current ESSID. This allows scan requests for specific ESSID
- * without having to change the current ESSID and potentially breaking
- * the current association.
- */
- __u8 essid[IW_ESSID_MAX_SIZE];
-
- /*
- * Optional parameters for changing the default scanning behavior.
- * These are based on the MLME-SCAN.request from IEEE Std 802.11.
- * TU is 1.024 ms. If these are set to 0, driver is expected to use
- * reasonable default values. min_channel_time defines the time that
- * will be used to wait for the first reply on each channel. If no
- * replies are received, next channel will be scanned after this. If
- * replies are received, total time waited on the channel is defined by
- * max_channel_time.
- */
- __u32 min_channel_time; /* in TU */
- __u32 max_channel_time; /* in TU */
-
- struct iw_freq channel_list[IW_MAX_FREQUENCIES];
-};
-
-/* ------------------------- WPA SUPPORT ------------------------- */
-
-/*
- * Extended data structure for get/set encoding (this is used with
- * SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_*
- * flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and
- * only the data contents changes (key data -> this structure, including
- * key data).
- *
- * If the new key is the first group key, it will be set as the default
- * TX key. Otherwise, default TX key index is only changed if
- * IW_ENCODE_EXT_SET_TX_KEY flag is set.
- *
- * Key will be changed with SIOCSIWENCODEEXT in all cases except for
- * special "change TX key index" operation which is indicated by setting
- * key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY.
- *
- * tx_seq/rx_seq are only used when respective
- * IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal
- * TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start
- * TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally
- * used only by an Authenticator (AP or an IBSS station) to get the
- * current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and
- * RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for
- * debugging/testing.
- */
-struct iw_encode_ext
-{
- __u32 ext_flags; /* IW_ENCODE_EXT_* */
- __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
- __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
- struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast
- * (group) keys or unicast address for
- * individual keys */
- __u16 alg; /* IW_ENCODE_ALG_* */
- __u16 key_len;
- __u8 key[0];
-};
-
-/* SIOCSIWMLME data */
-struct iw_mlme
-{
- __u16 cmd; /* IW_MLME_* */
- __u16 reason_code;
- struct sockaddr addr;
-};
-
-/* SIOCSIWPMKSA data */
-#define IW_PMKSA_ADD 1
-#define IW_PMKSA_REMOVE 2
-#define IW_PMKSA_FLUSH 3
-
-#define IW_PMKID_LEN 16
-
-struct iw_pmksa
-{
- __u32 cmd; /* IW_PMKSA_* */
- struct sockaddr bssid;
- __u8 pmkid[IW_PMKID_LEN];
-};
-
-/* IWEVMICHAELMICFAILURE data */
-struct iw_michaelmicfailure
-{
- __u32 flags;
- struct sockaddr src_addr;
- __u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-};
-
-/* IWEVPMKIDCAND data */
-#define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */
-struct iw_pmkid_cand
-{
- __u32 flags; /* IW_PMKID_CAND_* */
- __u32 index; /* the smaller the index, the higher the
- * priority */
- struct sockaddr bssid;
-};
-
-/* ------------------------ WIRELESS STATS ------------------------ */
-/*
- * Wireless statistics (used for /proc/net/wireless)
- */
-struct iw_statistics
-{
- __u16 status; /* Status
- * - device dependent for now */
-
- struct iw_quality qual; /* Quality of the link
- * (instant/mean/max) */
- struct iw_discarded discard; /* Packet discarded counts */
- struct iw_missed miss; /* Packet missed counts */
-};
-
-/* ------------------------ IOCTL REQUEST ------------------------ */
-/*
- * This structure defines the payload of an ioctl, and is used
- * below.
- *
- * Note that this structure should fit on the memory footprint
- * of iwreq (which is the same as ifreq), which mean a max size of
- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
- * You should check this when increasing the structures defined
- * above in this file...
- */
-union iwreq_data
-{
- /* Config - generic */
- char name[IFNAMSIZ];
- /* Name : used to verify the presence of wireless extensions.
- * Name of the protocol/provider... */
-
- struct iw_point essid; /* Extended network name */
- struct iw_param nwid; /* network id (or domain - the cell) */
- struct iw_freq freq; /* frequency or channel :
- * 0-1000 = channel
- * > 1000 = frequency in Hz */
-
- struct iw_param sens; /* signal level threshold */
- struct iw_param bitrate; /* default bit rate */
- struct iw_param txpower; /* default transmit power */
- struct iw_param rts; /* RTS threshold threshold */
- struct iw_param frag; /* Fragmentation threshold */
- __u32 mode; /* Operation mode */
- struct iw_param retry; /* Retry limits & lifetime */
-
- struct iw_point encoding; /* Encoding stuff : tokens */
- struct iw_param power; /* PM duration/timeout */
- struct iw_quality qual; /* Quality part of statistics */
-
- struct sockaddr ap_addr; /* Access point address */
- struct sockaddr addr; /* Destination address (hw/mac) */
-
- struct iw_param param; /* Other small parameters */
- struct iw_point data; /* Other large parameters */
-};
-
-/*
- * The structure to exchange data for ioctl.
- * This structure is the same as 'struct ifreq', but (re)defined for
- * convenience...
- * Do I need to remind you about structure size (32 octets) ?
- */
-struct iwreq
-{
- union
- {
- char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */
- } ifr_ifrn;
-
- /* Data part (defined just above) */
- union iwreq_data u;
-};
-
-/* -------------------------- IOCTL DATA -------------------------- */
-/*
- * For those ioctl which want to exchange mode data that what could
- * fit in the above structure...
- */
-
-/*
- * Range of parameters
- */
-
-struct iw_range
-{
- /* Informative stuff (to choose between different interface) */
- __u32 throughput; /* To give an idea... */
- /* In theory this value should be the maximum benchmarked
- * TCP/IP throughput, because with most of these devices the
- * bit rate is meaningless (overhead an co) to estimate how
- * fast the connection will go and pick the fastest one.
- * I suggest people to play with Netperf or any benchmark...
- */
-
- /* NWID (or domain id) */
- __u32 min_nwid; /* Minimal NWID we are able to set */
- __u32 max_nwid; /* Maximal NWID we are able to set */
-
- /* Old Frequency (backward compat - moved lower ) */
- __u16 old_num_channels;
- __u8 old_num_frequency;
-
- /* Scan capabilities */
- __u8 scan_capa; /* IW_SCAN_CAPA_* bit field */
-
- /* Wireless event capability bitmasks */
- __u32 event_capa[6];
-
- /* signal level threshold range */
- __s32 sensitivity;
-
- /* Quality of link & SNR stuff */
- /* Quality range (link, level, noise)
- * If the quality is absolute, it will be in the range [0 ; max_qual],
- * if the quality is dBm, it will be in the range [max_qual ; 0].
- * Don't forget that we use 8 bit arithmetics... */
- struct iw_quality max_qual; /* Quality of the link */
- /* This should contain the average/typical values of the quality
- * indicator. This should be the threshold between a "good" and
- * a "bad" link (example : monitor going from green to orange).
- * Currently, user space apps like quality monitors don't have any
- * way to calibrate the measurement. With this, they can split
- * the range between 0 and max_qual in different quality level
- * (using a geometric subdivision centered on the average).
- * I expect that people doing the user space apps will feedback
- * us on which value we need to put in each driver... */
- struct iw_quality avg_qual; /* Quality of the link */
-
- /* Rates */
- __u8 num_bitrates; /* Number of entries in the list */
- __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */
-
- /* RTS threshold */
- __s32 min_rts; /* Minimal RTS threshold */
- __s32 max_rts; /* Maximal RTS threshold */
-
- /* Frag threshold */
- __s32 min_frag; /* Minimal frag threshold */
- __s32 max_frag; /* Maximal frag threshold */
-
- /* Power Management duration & timeout */
- __s32 min_pmp; /* Minimal PM period */
- __s32 max_pmp; /* Maximal PM period */
- __s32 min_pmt; /* Minimal PM timeout */
- __s32 max_pmt; /* Maximal PM timeout */
- __u16 pmp_flags; /* How to decode max/min PM period */
- __u16 pmt_flags; /* How to decode max/min PM timeout */
- __u16 pm_capa; /* What PM options are supported */
-
- /* Encoder stuff */
- __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */
- __u8 num_encoding_sizes; /* Number of entry in the list */
- __u8 max_encoding_tokens; /* Max number of tokens */
- /* For drivers that need a "login/passwd" form */
- __u8 encoding_login_index; /* token index for login token */
-
- /* Transmit power */
- __u16 txpower_capa; /* What options are supported */
- __u8 num_txpower; /* Number of entries in the list */
- __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */
-
- /* Wireless Extension version info */
- __u8 we_version_compiled; /* Must be WIRELESS_EXT */
- __u8 we_version_source; /* Last update of source */
-
- /* Retry limits and lifetime */
- __u16 retry_capa; /* What retry options are supported */
- __u16 retry_flags; /* How to decode max/min retry limit */
- __u16 r_time_flags; /* How to decode max/min retry life */
- __s32 min_retry; /* Minimal number of retries */
- __s32 max_retry; /* Maximal number of retries */
- __s32 min_r_time; /* Minimal retry lifetime */
- __s32 max_r_time; /* Maximal retry lifetime */
-
- /* Frequency */
- __u16 num_channels; /* Number of channels [0; num - 1] */
- __u8 num_frequency; /* Number of entry in the list */
- struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */
- /* Note : this frequency list doesn't need to fit channel numbers,
- * because each entry contain its channel index */
-
- __u32 enc_capa; /* IW_ENC_CAPA_* bit field */
-};
-
-/*
- * Private ioctl interface information
- */
-
-struct iw_priv_args
-{
- __u32 cmd; /* Number of the ioctl to issue */
- __u16 set_args; /* Type and number of args */
- __u16 get_args; /* Type and number of args */
- char name[IFNAMSIZ]; /* Name of the extension */
-};
-
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/*
- * Wireless events are carried through the rtnetlink socket to user
- * space. They are encapsulated in the IFLA_WIRELESS field of
- * a RTM_NEWLINK message.
- */
-
-/*
- * A Wireless Event. Contains basically the same data as the ioctl...
- */
-struct iw_event
-{
- __u16 len; /* Real length of this stuff */
- __u16 cmd; /* Wireless IOCTL */
- union iwreq_data u; /* IOCTL fixed payload */
-};
-
-/* Size of the Event prefix (including padding and alignement junk) */
-#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data))
-/* Size of the various events */
-#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ)
-#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32))
-#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq))
-#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param))
-#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr))
-#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality))
-
-/* iw_point events are special. First, the payload (extra data) come at
- * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second,
- * we omit the pointer, so start at an offset. */
-#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \
- (char *) NULL)
-#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \
- IW_EV_POINT_OFF)
-
-#ifdef __KERNEL__
-#ifdef CONFIG_COMPAT
-struct __compat_iw_event {
- __u16 len; /* Real length of this stuff */
- __u16 cmd; /* Wireless IOCTL */
- compat_caddr_t pointer;
-};
-#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer)
-#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length)
-
-/* Size of the various events for compat */
-#define IW_EV_COMPAT_CHAR_LEN (IW_EV_COMPAT_LCP_LEN + IFNAMSIZ)
-#define IW_EV_COMPAT_UINT_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(__u32))
-#define IW_EV_COMPAT_FREQ_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq))
-#define IW_EV_COMPAT_PARAM_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param))
-#define IW_EV_COMPAT_ADDR_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr))
-#define IW_EV_COMPAT_QUAL_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality))
-#define IW_EV_COMPAT_POINT_LEN \
- (IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \
- IW_EV_COMPAT_POINT_OFF)
-#endif
-#endif
-
-/* Size of the Event prefix when packed in stream */
-#define IW_EV_LCP_PK_LEN (4)
-/* Size of the various events when packed in stream */
-#define IW_EV_CHAR_PK_LEN (IW_EV_LCP_PK_LEN + IFNAMSIZ)
-#define IW_EV_UINT_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(__u32))
-#define IW_EV_FREQ_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_freq))
-#define IW_EV_PARAM_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_param))
-#define IW_EV_ADDR_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct sockaddr))
-#define IW_EV_QUAL_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_quality))
-#define IW_EV_POINT_PK_LEN (IW_EV_LCP_PK_LEN + 4)
-
-#endif /* _LINUX_WIRELESS_H */
diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c
index 4de34a8..d3406f3 100644
--- a/src/eap_common/eap_fast_common.c
+++ b/src/eap_common/eap_fast_common.c
@@ -133,9 +133,9 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
"expansion", keys.master_key, keys.master_key_len);
- if (tls_prf(keys.master_key, keys.master_key_len,
- label, rnd, keys.client_random_len +
- keys.server_random_len, out, block_size + len))
+ if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+ label, rnd, keys.client_random_len +
+ keys.server_random_len, out, block_size + len))
goto fail;
os_free(rnd);
os_memmove(out, out + block_size, len);
diff --git a/src/eap_common/eap_peap_common.c b/src/eap_common/eap_peap_common.c
index 3a64b8e..8a701d2 100644
--- a/src/eap_common/eap_peap_common.c
+++ b/src/eap_common/eap_peap_common.c
@@ -1,6 +1,6 @@
/*
* EAP-PEAP common routines
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,9 +18,9 @@
#include "crypto/sha1.h"
#include "eap_peap_common.h"
-void peap_prfplus(int version, const u8 *key, size_t key_len,
- const char *label, const u8 *seed, size_t seed_len,
- u8 *buf, size_t buf_len)
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *buf, size_t buf_len)
{
unsigned char counter = 0;
size_t pos, plen;
@@ -75,7 +75,8 @@ void peap_prfplus(int version, const u8 *key, size_t key_len,
while (pos < buf_len) {
counter++;
plen = buf_len - pos;
- hmac_sha1_vector(key, key_len, 5, addr, len, hash);
+ if (hmac_sha1_vector(key, key_len, 5, addr, len, hash) < 0)
+ return -1;
if (plen >= SHA1_MAC_LEN) {
os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
pos += SHA1_MAC_LEN;
@@ -85,4 +86,6 @@ void peap_prfplus(int version, const u8 *key, size_t key_len,
}
len[0] = SHA1_MAC_LEN;
}
+
+ return 0;
}
diff --git a/src/eap_common/eap_peap_common.h b/src/eap_common/eap_peap_common.h
index f59afb0..f182078 100644
--- a/src/eap_common/eap_peap_common.h
+++ b/src/eap_common/eap_peap_common.h
@@ -1,6 +1,6 @@
/*
* EAP-PEAP common routines
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,8 +15,8 @@
#ifndef EAP_PEAP_COMMON_H
#define EAP_PEAP_COMMON_H
-void peap_prfplus(int version, const u8 *key, size_t key_len,
- const char *label, const u8 *seed, size_t seed_len,
- u8 *buf, size_t buf_len);
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *buf, size_t buf_len);
#endif /* EAP_PEAP_COMMON_H */
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index c24b146..0dbdff2 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -75,8 +75,8 @@ void eap_pwd_kdf(u8 *key, int keylen, u8 *label, int labellen,
/* since we're expanding to a bit length, mask off the excess */
if (resultbitlen % 8) {
- mask >>= ((resultbytelen * 8) - resultbitlen);
- result[0] &= mask;
+ mask <<= (8 - (resultbitlen % 8));
+ result[resultbytelen - 1] &= mask;
}
}
@@ -189,6 +189,18 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
prfbuf, primebitlen);
BN_bin2bn(prfbuf, primebytelen, x_candidate);
+
+ /*
+ * eap_pwd_kdf() returns a string of bits 0..primebitlen but
+ * BN_bin2bn will treat that string of bits as a big endian
+ * number. If the primebitlen is not an even multiple of 8
+ * then excessive bits-- those _after_ primebitlen-- so now
+ * we have to shift right the amount we masked off.
+ */
+ if (primebitlen % 8)
+ BN_rshift(x_candidate, x_candidate,
+ (8 - (primebitlen % 8)));
+
if (BN_ucmp(x_candidate, grp->prime) >= 0)
continue;
@@ -272,6 +284,7 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k,
u8 mk[SHA256_DIGEST_LENGTH], *cruft;
u8 session_id[SHA256_DIGEST_LENGTH + 1];
u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
+ int offset;
if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL)
return -1;
@@ -283,16 +296,21 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k,
session_id[0] = EAP_TYPE_PWD;
H_Init(&ctx);
H_Update(&ctx, (u8 *)ciphersuite, sizeof(u32));
- BN_bn2bin(peer_scalar, cruft);
+ offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar);
+ os_memset(cruft, 0, BN_num_bytes(grp->prime));
+ BN_bn2bin(peer_scalar, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(grp->order));
- BN_bn2bin(server_scalar, cruft);
+ offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar);
+ os_memset(cruft, 0, BN_num_bytes(grp->prime));
+ BN_bn2bin(server_scalar, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(grp->order));
H_Final(&ctx, &session_id[1]);
/* then compute MK = H(k | commit-peer | commit-server) */
H_Init(&ctx);
+ offset = BN_num_bytes(grp->prime) - BN_num_bytes(k);
os_memset(cruft, 0, BN_num_bytes(grp->prime));
- BN_bn2bin(k, cruft);
+ BN_bn2bin(k, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(grp->prime));
H_Update(&ctx, commit_peer, SHA256_DIGEST_LENGTH);
H_Update(&ctx, commit_server, SHA256_DIGEST_LENGTH);
diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h
index 971386d..4b841b7 100644
--- a/src/eap_common/eap_pwd_common.h
+++ b/src/eap_common/eap_pwd_common.h
@@ -35,13 +35,8 @@ typedef struct group_definition_ {
/*
* EAP-pwd header, included on all payloads
+ * L(1 bit) | M(1 bit) | exch(6 bits) | total_length(if L is set)
*/
-struct eap_pwd_hdr {
- u8 l_bit:1;
- u8 m_bit:1;
- u8 exch:6;
- u8 total_length[0]; /* included when l_bit is set */
-} STRUCT_PACKED;
#define EAP_PWD_OPCODE_ID_EXCH 1
#define EAP_PWD_OPCODE_COMMIT_EXCH 2
diff --git a/src/eap_common/ikev2_common.h b/src/eap_common/ikev2_common.h
index c96a070..31a2b0d 100644
--- a/src/eap_common/ikev2_common.h
+++ b/src/eap_common/ikev2_common.h
@@ -139,7 +139,7 @@ enum {
IKEV2_TRANSFORM_ESN = 5
};
-/* IKEv2 Tranform Type 1 (Encryption Algorithm) */
+/* IKEv2 Transform Type 1 (Encryption Algorithm) */
enum {
ENCR_DES_IV64 = 1,
ENCR_DES = 2,
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index ecfaf30..91fa4a9 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -147,6 +147,7 @@ SM_STATE(EAP, INITIALIZE)
sm->methodState = METHOD_NONE;
sm->allowNotifications = TRUE;
sm->decision = DECISION_FAIL;
+ sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
eapol_set_bool(sm, EAPOL_eapFail, FALSE);
@@ -1242,6 +1243,7 @@ struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
#endif /* CONFIG_FIPS */
tlsconf.event_cb = eap_peer_sm_tls_event;
tlsconf.cb_ctx = sm;
+ tlsconf.cert_in_cb = conf->cert_in_cb;
sm->ssl_ctx = tls_init(&tlsconf);
if (sm->ssl_ctx == NULL) {
wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
@@ -1466,16 +1468,11 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-typedef enum {
- TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
- TYPE_PASSPHRASE
-} eap_ctrl_req_type;
-
-static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
+static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
const char *msg, size_t msglen)
{
struct eap_peer_config *config;
- char *field, *txt, *tmp;
+ char *txt = NULL, *tmp;
if (sm == NULL)
return;
@@ -1483,29 +1480,20 @@ static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
if (config == NULL)
return;
- switch (type) {
- case TYPE_IDENTITY:
- field = "IDENTITY";
- txt = "Identity";
+ switch (field) {
+ case WPA_CTRL_REQ_EAP_IDENTITY:
config->pending_req_identity++;
break;
- case TYPE_PASSWORD:
- field = "PASSWORD";
- txt = "Password";
+ case WPA_CTRL_REQ_EAP_PASSWORD:
config->pending_req_password++;
break;
- case TYPE_NEW_PASSWORD:
- field = "NEW_PASSWORD";
- txt = "New Password";
+ case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
config->pending_req_new_password++;
break;
- case TYPE_PIN:
- field = "PIN";
- txt = "PIN";
+ case WPA_CTRL_REQ_EAP_PIN:
config->pending_req_pin++;
break;
- case TYPE_OTP:
- field = "OTP";
+ case WPA_CTRL_REQ_EAP_OTP:
if (msg) {
tmp = os_malloc(msglen + 3);
if (tmp == NULL)
@@ -1524,9 +1512,7 @@ static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
txt = config->pending_req_otp;
}
break;
- case TYPE_PASSPHRASE:
- field = "PASSPHRASE";
- txt = "Private key passphrase";
+ case WPA_CTRL_REQ_EAP_PASSPHRASE:
config->pending_req_passphrase++;
break;
default:
@@ -1559,7 +1545,7 @@ const char * eap_sm_get_method_name(struct eap_sm *sm)
*/
void eap_sm_request_identity(struct eap_sm *sm)
{
- eap_sm_request(sm, TYPE_IDENTITY, NULL, 0);
+ eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0);
}
@@ -1574,7 +1560,7 @@ void eap_sm_request_identity(struct eap_sm *sm)
*/
void eap_sm_request_password(struct eap_sm *sm)
{
- eap_sm_request(sm, TYPE_PASSWORD, NULL, 0);
+ eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSWORD, NULL, 0);
}
@@ -1589,7 +1575,7 @@ void eap_sm_request_password(struct eap_sm *sm)
*/
void eap_sm_request_new_password(struct eap_sm *sm)
{
- eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0);
+ eap_sm_request(sm, WPA_CTRL_REQ_EAP_NEW_PASSWORD, NULL, 0);
}
@@ -1604,7 +1590,7 @@ void eap_sm_request_new_password(struct eap_sm *sm)
*/
void eap_sm_request_pin(struct eap_sm *sm)
{
- eap_sm_request(sm, TYPE_PIN, NULL, 0);
+ eap_sm_request(sm, WPA_CTRL_REQ_EAP_PIN, NULL, 0);
}
@@ -1620,7 +1606,7 @@ void eap_sm_request_pin(struct eap_sm *sm)
*/
void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
{
- eap_sm_request(sm, TYPE_OTP, msg, msg_len);
+ eap_sm_request(sm, WPA_CTRL_REQ_EAP_OTP, msg, msg_len);
}
@@ -1635,7 +1621,7 @@ void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
*/
void eap_sm_request_passphrase(struct eap_sm *sm)
{
- eap_sm_request(sm, TYPE_PASSPHRASE, NULL, 0);
+ eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSPHRASE, NULL, 0);
}
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 2a80d4e..f35197f 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -216,10 +216,10 @@ struct eapol_callbacks {
/**
* eap_param_needed - Notify that EAP parameter is needed
* @ctx: eapol_ctx from eap_peer_sm_init() call
- * @field: Field name (e.g., "IDENTITY")
+ * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
* @txt: User readable text describing the required parameter
*/
- void (*eap_param_needed)(void *ctx, const char *field,
+ void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
const char *txt);
/**
@@ -262,6 +262,11 @@ struct eap_config {
* This is only used by EAP-WSC and can be left %NULL if not available.
*/
struct wps_context *wps;
+
+ /**
+ * cert_in_cb - Include server certificates in callback
+ */
+ int cert_in_cb;
};
struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 182f01a..766764b 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -235,21 +235,20 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
{
- wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s",
- id & CLEAR_PSEUDONYM ? " pseudonym" : "",
- id & CLEAR_REAUTH_ID ? " reauth_id" : "",
- id & CLEAR_EAP_ID ? " eap_id" : "");
if (id & CLEAR_PSEUDONYM) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
}
if (id & CLEAR_REAUTH_ID) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
os_free(data->reauth_id);
data->reauth_id = NULL;
data->reauth_id_len = 0;
}
if (id & CLEAR_EAP_ID) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id");
os_free(data->last_eap_identity);
data->last_eap_identity = NULL;
data->last_eap_identity_len = 0;
@@ -880,11 +879,11 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
- /* Old reauthentication and pseudonym identities must not be used
- * anymore. In other words, if no new identities are received, full
- * authentication will be used on next reauthentication. */
- eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
- CLEAR_EAP_ID);
+ /* Old reauthentication identity must not be used anymore. In
+ * other words, if no new identities are received, full
+ * authentication will be used on next reauthentication (using
+ * pseudonym identity or permanent identity). */
+ eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
if (attr->encr_data) {
u8 *decrypted;
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 5d3e69d..3cfb41a 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -444,8 +444,9 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
return 0;
}
- if (data->phase2_priv == NULL &&
- eap_fast_init_phase2_method(sm, data) < 0) {
+ if ((data->phase2_priv == NULL &&
+ eap_fast_init_phase2_method(sm, data) < 0) ||
+ data->phase2_method == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
"Phase 2 EAP method %d", *pos);
ret->methodState = METHOD_DONE;
@@ -542,7 +543,7 @@ static struct wpabuf * eap_fast_tlv_pac_ack(void)
static struct wpabuf * eap_fast_process_eap_payload_tlv(
struct eap_sm *sm, struct eap_fast_data *data,
- struct eap_method_ret *ret, const struct eap_hdr *req,
+ struct eap_method_ret *ret,
u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
{
struct eap_hdr *hdr;
@@ -1037,11 +1038,15 @@ static struct wpabuf * eap_fast_process_pac(struct eap_sm *sm,
} else {
/*
* This is PAC refreshing, i.e., normal authentication that is
- * expected to be completed with an EAP-Success.
+ * expected to be completed with an EAP-Success. However,
+ * RFC 5422, Section 3.5 allows EAP-Failure to be sent even
+ * after protected success exchange in case of EAP-Fast
+ * provisioning, so we better use DECISION_COND_SUCC here
+ * instead of DECISION_UNCOND_SUCC.
*/
wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
"- PAC refreshing completed successfully");
- ret->decision = DECISION_UNCOND_SUCC;
+ ret->decision = DECISION_COND_SUCC;
}
ret->methodState = METHOD_DONE;
return eap_fast_tlv_pac_ack();
@@ -1184,7 +1189,7 @@ static int eap_fast_process_decrypted(struct eap_sm *sm,
if (tlv.eap_payload_tlv) {
tmp = eap_fast_process_eap_payload_tlv(
- sm, data, ret, req, tlv.eap_payload_tlv,
+ sm, data, ret, tlv.eap_payload_tlv,
tlv.eap_payload_tlv_len);
resp = wpabuf_concat(resp, tmp);
}
diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c
index 3b0af05..937fd45 100644
--- a/src/eap_peer/eap_methods.c
+++ b/src/eap_peer/eap_methods.c
@@ -77,6 +77,8 @@ EapType eap_peer_get_type(const char *name, int *vendor)
const char * eap_get_name(int vendor, EapType type)
{
struct eap_method *m;
+ if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
+ return "expanded";
for (m = eap_methods; m; m = m->next) {
if (m->vendor == vendor && m->method == type)
return m->name;
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 2b72084..7cb8213 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -196,7 +196,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
* @nak_type: TLV type (EAP_TLV_*)
* Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
*
- * This funtion builds an EAP-TLV NAK message. The caller is responsible for
+ * This function builds an EAP-TLV NAK message. The caller is responsible for
* freeing the returned buffer.
*/
static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
@@ -285,8 +285,10 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
* in the end of the label just before ISK; is that just a typo?)
*/
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
- peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck));
+ if (peap_prfplus(data->peap_version, tk, 40,
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck)) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
imck, sizeof(imck));
@@ -346,8 +348,8 @@ static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
* @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
* Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
*
- * This funtion builds an EAP-TLV Result message. The caller is responsible for
- * freeing the returned buffer.
+ * This function builds an EAP-TLV Result message. The caller is responsible
+ * for freeing the returned buffer.
*/
static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
struct eap_peap_data *data,
@@ -1247,9 +1249,12 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
* termination for this label while the one used for deriving
* IPMK|CMK did not use null termination.
*/
- peap_prfplus(data->peap_version, data->ipmk, 40,
- "Session Key Generating Function",
- (u8 *) "\00", 1, csk, sizeof(csk));
+ if (peap_prfplus(data->peap_version, data->ipmk, 40,
+ "Session Key Generating Function",
+ (u8 *) "\00", 1, csk, sizeof(csk)) < 0) {
+ os_free(key);
+ return NULL;
+ }
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
os_memcpy(key, csk, EAP_TLS_KEY_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index e4705b7..1957c82 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -423,8 +423,7 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
- sizeof(struct eap_pwd_hdr) +
- BN_num_bytes(data->grp->order) +
+ 1 + BN_num_bytes(data->grp->order) +
(2 * BN_num_bytes(data->grp->prime)),
EAP_CODE_RESPONSE, eap_get_id(reqData));
if (resp == NULL)
@@ -465,6 +464,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
u32 cs;
u16 grp;
u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+ int offset;
/*
* first build up the ciphersuite which is group | random_function |
@@ -497,7 +497,8 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
* value may start with a few zeros and the previous one did not.
*/
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->k, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+ BN_bn2bin(data->k, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* server element: x, y */
@@ -509,15 +510,19 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
goto fin;
}
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(x, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(y, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* server scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->server_scalar, cruft);
+ offset = BN_num_bytes(data->grp->order) -
+ BN_num_bytes(data->server_scalar);
+ BN_bn2bin(data->server_scalar, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
/* my element: x, y */
@@ -530,15 +535,19 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
}
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(x, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(y, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* my scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->my_scalar, cruft);
+ offset = BN_num_bytes(data->grp->order) -
+ BN_num_bytes(data->my_scalar);
+ BN_bn2bin(data->my_scalar, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
/* the ciphersuite */
@@ -564,7 +573,8 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
/* k */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->k, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+ BN_bn2bin(data->k, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* my element */
@@ -576,15 +586,19 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
goto fin;
}
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(x, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(y, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* my scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->my_scalar, cruft);
+ offset = BN_num_bytes(data->grp->order) -
+ BN_num_bytes(data->my_scalar);
+ BN_bn2bin(data->my_scalar, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
/* server element: x, y */
@@ -596,15 +610,19 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
goto fin;
}
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(x, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(y, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* server scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->server_scalar, cruft);
+ offset = BN_num_bytes(data->grp->order) -
+ BN_num_bytes(data->server_scalar);
+ BN_bn2bin(data->server_scalar, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
/* the ciphersuite */
@@ -614,7 +632,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
H_Final(&ctx, conf);
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
- sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH,
+ 1 + SHA256_DIGEST_LENGTH,
EAP_CODE_RESPONSE, eap_get_id(reqData));
if (resp == NULL)
goto fin;
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index 6677063..06fbc5b 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -266,21 +266,20 @@ static int eap_sim_supported_ver(int version)
static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
{
- wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old%s%s%s",
- id & CLEAR_PSEUDONYM ? " pseudonym" : "",
- id & CLEAR_REAUTH_ID ? " reauth_id" : "",
- id & CLEAR_EAP_ID ? " eap_id" : "");
- if (id & CLEAR_PSEUDONYM) {
+ if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym");
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
}
- if (id & CLEAR_REAUTH_ID) {
+ if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
os_free(data->reauth_id);
data->reauth_id = NULL;
data->reauth_id_len = 0;
}
- if (id & CLEAR_EAP_ID) {
+ if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id");
os_free(data->last_eap_identity);
data->last_eap_identity = NULL;
data->last_eap_identity_len = 0;
@@ -649,11 +648,11 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
- /* Old reauthentication and pseudonym identities must not be used
- * anymore. In other words, if no new identities are received, full
- * authentication will be used on next reauthentication. */
- eap_sim_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
- CLEAR_EAP_ID);
+ /* Old reauthentication identity must not be used anymore. In
+ * other words, if no new reauth identity is received, full
+ * authentication will be used on next reauthentication (using
+ * pseudonym identity or permanent identity). */
+ eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
if (attr->encr_data) {
u8 *decrypted;
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index d1567e9..2934ba4 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -112,7 +112,6 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
eap_tls_params_from_conf1(params, config);
}
- params->tls_ia = data->tls_ia;
/*
* Use blob data, if available. Otherwise, leave reference to external
@@ -295,9 +294,9 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
os_memcpy(rnd + keys.client_random_len, keys.server_random,
keys.server_random_len);
- if (tls_prf(keys.master_key, keys.master_key_len,
- label, rnd, keys.client_random_len +
- keys.server_random_len, out, len))
+ if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+ label, rnd, keys.client_random_len +
+ keys.server_random_len, out, len))
goto fail;
os_free(rnd);
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index e9e0998..e9a07b8 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -66,11 +66,6 @@ struct eap_ssl_data {
int include_tls_length;
/**
- * tls_ia - Whether TLS/IA is enabled for this TLS connection
- */
- int tls_ia;
-
- /**
* eap - EAP state machine allocated with eap_peer_sm_init()
*/
struct eap_sm *eap;
diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c
index 6c95f72..da288eb 100644
--- a/src/eap_peer/eap_tnc.c
+++ b/src/eap_peer/eap_tnc.c
@@ -15,7 +15,6 @@
#include "includes.h"
#include "common.h"
-#include "base64.h"
#include "eap_i.h"
#include "tncc.h"
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index e8f0f38..612dfa7 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,17 +26,7 @@
#include "eap_config.h"
-/* Maximum supported TTLS version
- * 0 = RFC 5281
- * 1 = draft-funk-eap-ttls-v1-00.txt
- */
-#ifndef EAP_TTLS_VERSION
-#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
-#endif /* EAP_TTLS_VERSION */
-
-
-#define MSCHAPV2_KEY_LEN 16
-#define MSCHAPV2_NT_RESPONSE_LEN 24
+#define EAP_TTLS_VERSION 0
static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
@@ -44,9 +34,8 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
struct eap_ttls_data {
struct eap_ssl_data ssl;
- int ssl_initialized;
- int ttls_version, force_ttls_version;
+ int ttls_version;
const struct eap_method *phase2_method;
void *phase2_priv;
@@ -91,22 +80,9 @@ static void * eap_ttls_init(struct eap_sm *sm)
if (data == NULL)
return NULL;
data->ttls_version = EAP_TTLS_VERSION;
- data->force_ttls_version = -1;
selected = "EAP";
data->phase2_type = EAP_TTLS_PHASE2_EAP;
-#if EAP_TTLS_VERSION > 0
- if (config && config->phase1) {
- const char *pos = os_strstr(config->phase1, "ttlsver=");
- if (pos) {
- data->force_ttls_version = atoi(pos + 8);
- data->ttls_version = data->force_ttls_version;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Forced TTLS version "
- "%d", data->force_ttls_version);
- }
- }
-#endif /* EAP_TTLS_VERSION */
-
if (config && config->phase2) {
if (os_strstr(config->phase2, "autheap=")) {
selected = "EAP";
@@ -140,19 +116,11 @@ static void * eap_ttls_init(struct eap_sm *sm)
data->phase2_eap_type.method = EAP_TYPE_NONE;
}
-#if EAP_TTLS_VERSION > 0
- if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
- data->ttls_version > 0) {
- if (data->force_ttls_version > 0) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
- "TLS library does not support TLS/IA.",
- data->force_ttls_version);
- eap_ttls_deinit(sm, data);
- return NULL;
- }
- data->ttls_version = 0;
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
+ eap_ttls_deinit(sm, data);
+ return NULL;
}
-#endif /* EAP_TTLS_VERSION */
return data;
}
@@ -176,8 +144,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
return;
eap_ttls_phase2_eap_deinit(sm, data);
os_free(data->phase2_eap_types);
- if (data->ssl_initialized)
- eap_peer_tls_ssl_deinit(sm, &data->ssl);
+ eap_peer_tls_ssl_deinit(sm, &data->ssl);
os_free(data->key_data);
wpabuf_free(data->pending_phase2_req);
os_free(data);
@@ -246,39 +213,6 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
}
-#if EAP_TTLS_VERSION > 0
-static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
- struct eap_ttls_data *data,
- const u8 *key, size_t key_len)
-{
- u8 *buf;
- size_t buf_len;
- int ret;
-
- if (key) {
- buf_len = 2 + key_len;
- buf = os_malloc(buf_len);
- if (buf == NULL)
- return -1;
- WPA_PUT_BE16(buf, key_len);
- os_memcpy(buf + 2, key, key_len);
- } else {
- buf = NULL;
- buf_len = 0;
- }
-
- wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
- "secret permutation", buf, buf_len);
- ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
- data->ssl.conn,
- buf, buf_len);
- os_free(buf);
-
- return ret;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
static int eap_ttls_v0_derive_key(struct eap_sm *sm,
struct eap_ttls_data *data)
{
@@ -298,156 +232,10 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm,
}
-#if EAP_TTLS_VERSION > 0
-static int eap_ttls_v1_derive_key(struct eap_sm *sm,
- struct eap_ttls_data *data)
-{
- struct tls_keys keys;
- u8 *rnd;
-
- os_free(data->key_data);
- data->key_data = NULL;
-
- os_memset(&keys, 0, sizeof(keys));
- if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
- keys.client_random == NULL || keys.server_random == NULL ||
- keys.inner_secret == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
- "client random, or server random to derive keying "
- "material");
- return -1;
- }
-
- rnd = os_malloc(keys.client_random_len + keys.server_random_len);
- data->key_data = os_malloc(EAP_TLS_KEY_LEN);
- if (rnd == NULL || data->key_data == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
- os_free(rnd);
- os_free(data->key_data);
- data->key_data = NULL;
- return -1;
- }
- os_memcpy(rnd, keys.client_random, keys.client_random_len);
- os_memcpy(rnd + keys.client_random_len, keys.server_random,
- keys.server_random_len);
-
- if (tls_prf(keys.inner_secret, keys.inner_secret_len,
- "ttls v1 keying material", rnd, keys.client_random_len +
- keys.server_random_len, data->key_data, EAP_TLS_KEY_LEN)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
- os_free(rnd);
- os_free(data->key_data);
- data->key_data = NULL;
- return -1;
- }
-
- wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
- rnd, keys.client_random_len + keys.server_random_len);
- wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
- keys.inner_secret, keys.inner_secret_len);
-
- os_free(rnd);
-
- wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
- data->key_data, EAP_TLS_KEY_LEN);
-
- return 0;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
struct eap_ttls_data *data, size_t len)
{
-#if EAP_TTLS_VERSION > 0
- struct tls_keys keys;
- u8 *challenge, *rnd;
-#endif /* EAP_TTLS_VERSION */
-
- if (data->ttls_version == 0) {
- return eap_peer_tls_derive_key(sm, &data->ssl,
- "ttls challenge", len);
- }
-
-#if EAP_TTLS_VERSION > 0
-
- os_memset(&keys, 0, sizeof(keys));
- if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
- keys.client_random == NULL || keys.server_random == NULL ||
- keys.inner_secret == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
- "client random, or server random to derive "
- "implicit challenge");
- return NULL;
- }
-
- rnd = os_malloc(keys.client_random_len + keys.server_random_len);
- challenge = os_malloc(len);
- if (rnd == NULL || challenge == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
- "challenge derivation");
- os_free(rnd);
- os_free(challenge);
- return NULL;
- }
- os_memcpy(rnd, keys.server_random, keys.server_random_len);
- os_memcpy(rnd + keys.server_random_len, keys.client_random,
- keys.client_random_len);
-
- if (tls_prf(keys.inner_secret, keys.inner_secret_len,
- "inner application challenge", rnd,
- keys.client_random_len + keys.server_random_len,
- challenge, len)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
- "challenge");
- os_free(rnd);
- os_free(challenge);
- return NULL;
- }
-
- os_free(rnd);
-
- wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
- challenge, len);
-
- return challenge;
-
-#else /* EAP_TTLS_VERSION */
-
- return NULL;
-
-#endif /* EAP_TTLS_VERSION */
-}
-
-
-static void eap_ttlsv1_phase2_eap_finish(struct eap_sm *sm,
- struct eap_ttls_data *data,
- struct eap_method_ret *ret)
-{
-#if EAP_TTLS_VERSION > 0
- if (data->ttls_version > 0) {
- const struct eap_method *m = data->phase2_method;
- void *priv = data->phase2_priv;
-
- /* TTLSv1 requires TLS/IA FinalPhaseFinished */
- if (ret->decision == DECISION_UNCOND_SUCC)
- ret->decision = DECISION_COND_SUCC;
- ret->methodState = METHOD_CONT;
-
- if (ret->decision == DECISION_COND_SUCC &&
- m->isKeyAvailable && m->getKey &&
- m->isKeyAvailable(sm, priv)) {
- u8 *key;
- size_t key_len;
- key = m->getKey(sm, priv, &key_len);
- if (key) {
- eap_ttls_ia_permute_inner_secret(
- sm, data, key, key_len);
- os_free(key);
- }
- }
- }
-#endif /* EAP_TTLS_VERSION */
+ return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len);
}
@@ -494,7 +282,6 @@ static int eap_ttls_phase2_eap_process(struct eap_sm *sm,
ret->methodState = iret.methodState;
ret->decision = iret.decision;
}
- eap_ttlsv1_phase2_eap_finish(sm, data, ret);
return 0;
}
@@ -615,26 +402,6 @@ static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
}
-static void eap_ttlsv1_permute_inner(struct eap_sm *sm,
- struct eap_ttls_data *data)
-{
-#if EAP_TTLS_VERSION > 0
- u8 session_key[2 * MSCHAPV2_KEY_LEN];
-
- if (data->ttls_version == 0)
- return;
-
- get_asymetric_start_key(data->master_key, session_key,
- MSCHAPV2_KEY_LEN, 0, 0);
- get_asymetric_start_key(data->master_key,
- session_key + MSCHAPV2_KEY_LEN,
- MSCHAPV2_KEY_LEN, 1, 0);
- eap_ttls_ia_permute_inner_secret(sm, data, session_key,
- sizeof(session_key));
-#endif /* EAP_TTLS_VERSION */
-}
-
-
static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
@@ -702,8 +469,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
}
data->auth_response_valid = 1;
- eap_ttlsv1_permute_inner(sm, data);
-
pos += 24;
os_free(challenge);
AVP_PAD(buf, pos);
@@ -711,7 +476,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
wpabuf_put(msg, pos - buf);
*resp = msg;
- if (sm->workaround && data->ttls_version == 0) {
+ if (sm->workaround) {
/* At least FreeRADIUS seems to be terminating
* EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
* packet. */
@@ -798,17 +563,10 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
wpabuf_put(msg, pos - buf);
*resp = msg;
- if (data->ttls_version > 0) {
- /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
- * so do not allow connection to be terminated yet. */
- ret->methodState = METHOD_CONT;
- ret->decision = DECISION_COND_SUCC;
- } else {
- /* EAP-TTLS/MSCHAP does not provide tunneled success
- * notification, so assume that Phase2 succeeds. */
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_COND_SUCC;
- }
+ /* EAP-TTLS/MSCHAP does not provide tunneled success
+ * notification, so assume that Phase2 succeeds. */
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_COND_SUCC;
return 0;
}
@@ -859,17 +617,10 @@ static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
wpabuf_put(msg, pos - buf);
*resp = msg;
- if (data->ttls_version > 0) {
- /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
- * so do not allow connection to be terminated yet. */
- ret->methodState = METHOD_CONT;
- ret->decision = DECISION_COND_SUCC;
- } else {
- /* EAP-TTLS/PAP does not provide tunneled success notification,
- * so assume that Phase2 succeeds. */
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_COND_SUCC;
- }
+ /* EAP-TTLS/PAP does not provide tunneled success notification,
+ * so assume that Phase2 succeeds. */
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_COND_SUCC;
return 0;
}
@@ -942,17 +693,10 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
wpabuf_put(msg, pos - buf);
*resp = msg;
- if (data->ttls_version > 0) {
- /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
- * so do not allow connection to be terminated yet. */
- ret->methodState = METHOD_CONT;
- ret->decision = DECISION_COND_SUCC;
- } else {
- /* EAP-TTLS/CHAP does not provide tunneled success
- * notification, so assume that Phase2 succeeds. */
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_COND_SUCC;
- }
+ /* EAP-TTLS/CHAP does not provide tunneled success
+ * notification, so assume that Phase2 succeeds. */
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_COND_SUCC;
return 0;
}
@@ -1027,36 +771,6 @@ static int eap_ttls_phase2_request(struct eap_sm *sm,
}
-#if EAP_TTLS_VERSION > 0
-static struct wpabuf * eap_ttls_build_phase_finished(
- struct eap_sm *sm, struct eap_ttls_data *data, int id, int final)
-{
- struct wpabuf *req, *buf;
-
- buf = tls_connection_ia_send_phase_finished(sm->ssl_ctx,
- data->ssl.conn,
- final);
- if (buf == NULL)
- return NULL;
-
- req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS,
- 1 + wpabuf_len(buf),
- EAP_CODE_RESPONSE, id);
- if (req == NULL) {
- wpabuf_free(buf);
- return NULL;
- }
-
- wpabuf_put_u8(req, data->ttls_version);
- wpabuf_put_buf(req, buf);
- wpabuf_free(buf);
- eap_update_len(req);
-
- return req;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
struct ttls_parse_avp {
u8 *mschapv2;
u8 *eapdata;
@@ -1366,19 +1080,9 @@ static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 "
"authentication succeeded");
- if (data->ttls_version > 0) {
- /*
- * EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report
- * success, so do not allow connection to be terminated
- * yet.
- */
- ret->methodState = METHOD_CONT;
- ret->decision = DECISION_COND_SUCC;
- } else {
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_UNCOND_SUCC;
- data->phase2_success = 1;
- }
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ data->phase2_success = 1;
/*
* Reply with empty data; authentication server will reply
@@ -1493,24 +1197,6 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm,
}
-#if EAP_TTLS_VERSION > 0
-static void eap_ttls_final_phase_finished(struct eap_sm *sm,
- struct eap_ttls_data *data,
- struct eap_method_ret *ret,
- u8 identifier,
- struct wpabuf **out_data)
-{
- wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished received");
- wpa_printf(MSG_INFO, "EAP-TTLS: TLS/IA authentication succeeded");
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_UNCOND_SUCC;
- data->phase2_success = 1;
- *out_data = eap_ttls_build_phase_finished(sm, data, identifier, 1);
- eap_ttls_v1_derive_key(sm, data);
-}
-#endif /* EAP_TTLS_VERSION */
-
-
static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
@@ -1534,6 +1220,21 @@ static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
"processing failed");
retval = -1;
} else {
+ struct eap_peer_config *config = eap_get_config(sm);
+ if (resp == NULL &&
+ (config->pending_req_identity ||
+ config->pending_req_password ||
+ config->pending_req_otp ||
+ config->pending_req_new_password)) {
+ /*
+ * Use empty buffer to force implicit request
+ * processing when EAP request is re-processed after
+ * user input.
+ */
+ wpabuf_free(data->pending_phase2_req);
+ data->pending_phase2_req = wpabuf_alloc(0);
+ }
+
retval = eap_ttls_encrypt_response(sm, data, resp, identifier,
out_data);
}
@@ -1627,17 +1328,6 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
if (retval)
goto done;
-#if EAP_TTLS_VERSION > 0
- if (data->ttls_version > 0 &&
- (in_decrypted == NULL || wpabuf_len(in_decrypted) == 0) &&
- tls_connection_ia_final_phase_finished(sm->ssl_ctx,
- data->ssl.conn)) {
- eap_ttls_final_phase_finished(sm, data, ret, identifier,
- out_data);
- goto done;
- }
-#endif /* EAP_TTLS_VERSION */
-
continue_req:
data->phase2_start = 0;
@@ -1662,46 +1352,6 @@ done:
}
-static int eap_ttls_process_start(struct eap_sm *sm,
- struct eap_ttls_data *data, u8 flags,
- struct eap_method_ret *ret)
-{
- struct eap_peer_config *config = eap_get_config(sm);
-
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)",
- flags & EAP_TLS_VERSION_MASK, data->ttls_version);
-#if EAP_TTLS_VERSION > 0
- if ((flags & EAP_TLS_VERSION_MASK) < data->ttls_version)
- data->ttls_version = flags & EAP_TLS_VERSION_MASK;
- if (data->force_ttls_version >= 0 &&
- data->force_ttls_version != data->ttls_version) {
- wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select "
- "forced TTLS version %d",
- data->force_ttls_version);
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
- return -1;
- }
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d",
- data->ttls_version);
-
- if (data->ttls_version > 0)
- data->ssl.tls_ia = 1;
-#endif /* EAP_TTLS_VERSION */
- if (!data->ssl_initialized &&
- eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
- return -1;
- }
- data->ssl_initialized = 1;
-
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Start");
-
- return 0;
-}
-
-
static int eap_ttls_process_handshake(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
@@ -1725,8 +1375,7 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
ret->methodState = METHOD_MAY_CONT;
}
data->phase2_start = 1;
- if (data->ttls_version == 0)
- eap_ttls_v0_derive_key(sm, data);
+ eap_ttls_v0_derive_key(sm, data);
if (*out_data == NULL || wpabuf_len(*out_data) == 0) {
if (eap_ttls_decrypt(sm, data, ret, identifier,
@@ -1761,7 +1410,7 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret)
{
- if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) {
+ if (ret->methodState == METHOD_DONE) {
ret->allowNotifications = FALSE;
if (ret->decision == DECISION_UNCOND_SUCC ||
ret->decision == DECISION_COND_SUCC) {
@@ -1779,8 +1428,7 @@ static void eap_ttls_check_auth_status(struct eap_sm *sm,
}
#endif /* EAP_TNC */
}
- } else if (data->ttls_version == 0 &&
- ret->methodState == METHOD_MAY_CONT &&
+ } else if (ret->methodState == METHOD_MAY_CONT &&
(ret->decision == DECISION_UNCOND_SUCC ||
ret->decision == DECISION_COND_SUCC)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
@@ -1808,8 +1456,9 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,
id = eap_get_id(reqData);
if (flags & EAP_TLS_FLAGS_START) {
- if (eap_ttls_process_start(sm, data, flags, ret) < 0)
- return NULL;
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own "
+ "ver=%d)", flags & EAP_TLS_VERSION_MASK,
+ data->ttls_version);
/* RFC 5281, Ch. 9.2:
* "This packet MAY contain additional information in the form
@@ -1817,13 +1466,6 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,
* For now, ignore any potential extra data.
*/
left = 0;
- } else if (!data->ssl_initialized) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: First message did not "
- "include Start flag");
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
- return NULL;
}
resp = NULL;
diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c
index 1e169a0..acd7611 100644
--- a/src/eap_peer/ikev2.c
+++ b/src/eap_peer/ikev2.c
@@ -425,7 +425,7 @@ static int ikev2_process_kei(struct ikev2_responder_data *data,
}
/* RFC 4306, Section 3.4:
- * The length of DH public value MUST be equal to the lenght of the
+ * The length of DH public value MUST be equal to the length of the
* prime modulus.
*/
if (kei_len - 4 != data->dh->prime_len) {
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index e1f500a..d5f8f1d 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -22,8 +22,6 @@
struct eap_sm;
-#define EAP_MAX_METHODS 8
-
#define EAP_TTLS_AUTH_PAP 1
#define EAP_TTLS_AUTH_CHAP 2
#define EAP_TTLS_AUTH_MSCHAP 4
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 3cba5aa..f48cf71 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -119,7 +119,7 @@ struct eap_sm {
/* Full authenticator state machine local variables */
- /* Long-term (maintained betwen packets) */
+ /* Long-term (maintained between packets) */
EapType currentMethod;
int currentId;
enum {
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 0f0da29..7a5beb6 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -136,6 +136,14 @@ SM_STATE(EAP, INITIALIZE)
{
SM_ENTRY(EAP, INITIALIZE);
+ if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
+ /*
+ * Need to allow internal Identity method to be used instead
+ * of passthrough at the beginning of reauthentication.
+ */
+ eap_server_clear_identity(sm);
+ }
+
sm->currentId = -1;
sm->eap_if.eapSuccess = FALSE;
sm->eap_if.eapFail = FALSE;
@@ -1028,9 +1036,12 @@ void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len)
not_found:
/* not found - remove from the list */
- os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
- (EAP_MAX_METHODS - i - 1) *
- sizeof(sm->user->methods[0]));
+ if (i + 1 < EAP_MAX_METHODS) {
+ os_memmove(&sm->user->methods[i],
+ &sm->user->methods[i + 1],
+ (EAP_MAX_METHODS - i - 1) *
+ sizeof(sm->user->methods[0]));
+ }
sm->user->methods[EAP_MAX_METHODS - 1].vendor =
EAP_VENDOR_IETF;
sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 42cbdce..0f25ffd 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -133,14 +133,13 @@ static void * eap_aka_prime_init(struct eap_sm *sm)
return NULL;
data->eap_method = EAP_TYPE_AKA_PRIME;
- data->network_name = os_malloc(os_strlen(network_name));
+ data->network_name = (u8 *) os_strdup(network_name);
if (data->network_name == NULL) {
os_free(data);
return NULL;
}
data->network_name_len = os_strlen(network_name);
- os_memcpy(data->network_name, network_name, data->network_name_len);
data->state = IDENTITY;
eap_aka_determine_identity(sm, data, 1, 0);
diff --git a/src/eap_server/eap_server_methods.c b/src/eap_server/eap_server_methods.c
index 900a5dd..4d241a4 100644
--- a/src/eap_server/eap_server_methods.c
+++ b/src/eap_server/eap_server_methods.c
@@ -167,6 +167,8 @@ void eap_server_unregister_methods(void)
const char * eap_server_get_name(int vendor, EapType type)
{
struct eap_method *m;
+ if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
+ return "expanded";
for (m = eap_methods; m; m = m->next) {
if (m->vendor == vendor && m->method == type)
return m->name;
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 64120a4..f5ee7f4 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -405,9 +405,12 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
if (sm->user->password_hash) {
pw_hash = sm->user->password;
} else {
- nt_password_hash(sm->user->password,
- sm->user->password_len,
- pw_hash_buf);
+ if (nt_password_hash(sm->user->password,
+ sm->user->password_len,
+ pw_hash_buf) < 0) {
+ data->state = FAILURE;
+ return;
+ }
pw_hash = pw_hash_buf;
}
generate_authenticator_response_pwhash(
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 8a7d626..50e79c0 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -351,8 +351,12 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
* in the end of the label just before ISK; is that just a typo?)
*/
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
- peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck));
+ if (peap_prfplus(data->peap_version, tk, 40,
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck)) < 0) {
+ os_free(tk);
+ return -1;
+ }
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
imck, sizeof(imck));
@@ -1060,8 +1064,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
in_decrypted);
- hdr = wpabuf_head(in_decrypted);
-
if (data->peap_version == 0 && data->state != PHASE2_TLV) {
const struct eap_hdr *resp;
struct eap_hdr *nhdr;
@@ -1320,9 +1322,10 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
* termination for this label while the one used for deriving
* IPMK|CMK did not use null termination.
*/
- peap_prfplus(data->peap_version, data->ipmk, 40,
- "Session Key Generating Function",
- (u8 *) "\00", 1, csk, sizeof(csk));
+ if (peap_prfplus(data->peap_version, data->ipmk, 40,
+ "Session Key Generating Function",
+ (u8 *) "\00", 1, csk, sizeof(csk)) < 0)
+ return NULL;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
if (eapKeyData) {
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index efc7a82..fb299ae 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -125,8 +125,10 @@ static struct wpabuf * eap_psk_build_3(struct eap_sm *sm,
os_memcpy(buf, data->id_s, data->id_s_len);
os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
- if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s))
+ if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
+ os_free(buf);
goto fail;
+ }
os_free(buf);
if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk,
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index dd2557a..4c6f4d1 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -156,8 +156,8 @@ eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request");
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
- sizeof(struct eap_pwd_hdr) +
- sizeof(struct eap_pwd_id) + data->id_server_len,
+ 1 + sizeof(struct eap_pwd_id) +
+ data->id_server_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
eap_pwd_state(data, FAILURE);
@@ -257,8 +257,7 @@ eap_pwd_build_commit_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
- sizeof(struct eap_pwd_hdr) +
- (2 * BN_num_bytes(data->grp->prime)) +
+ 1 + (2 * BN_num_bytes(data->grp->prime)) +
BN_num_bytes(data->grp->order),
EAP_CODE_REQUEST, id);
if (req == NULL)
@@ -289,6 +288,7 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
HMAC_CTX ctx;
u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
u16 grp;
+ int offset;
wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
@@ -313,7 +313,8 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
* First is k
*/
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->k, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+ BN_bn2bin(data->k, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* server element: x, y */
@@ -326,15 +327,19 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
}
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(x, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(y, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* server scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->my_scalar, cruft);
+ offset = BN_num_bytes(data->grp->order) -
+ BN_num_bytes(data->my_scalar);
+ BN_bn2bin(data->my_scalar, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
/* peer element: x, y */
@@ -347,15 +352,19 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
}
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(x, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(y, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* peer scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->peer_scalar, cruft);
+ offset = BN_num_bytes(data->grp->order) -
+ BN_num_bytes(data->peer_scalar);
+ BN_bn2bin(data->peer_scalar, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
/* ciphersuite */
@@ -375,7 +384,7 @@ eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
os_memcpy(data->my_confirm, conf, SHA256_DIGEST_LENGTH);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
- sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH,
+ 1 + SHA256_DIGEST_LENGTH,
EAP_CODE_REQUEST, id);
if (req == NULL)
goto fin;
@@ -624,6 +633,7 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
u32 cs;
u16 grp;
u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+ int offset;
/* build up the ciphersuite: group | random_function | prf */
grp = htons(data->group_num);
@@ -649,7 +659,8 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
/* k */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->k, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+ BN_bn2bin(data->k, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* peer element: x, y */
@@ -661,15 +672,19 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
goto fin;
}
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(x, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(y, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* peer scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->peer_scalar, cruft);
+ offset = BN_num_bytes(data->grp->order) -
+ BN_num_bytes(data->peer_scalar);
+ BN_bn2bin(data->peer_scalar, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
/* server element: x, y */
@@ -682,15 +697,19 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
}
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(x, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(y, cruft);
+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
/* server scalar */
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- BN_bn2bin(data->my_scalar, cruft);
+ offset = BN_num_bytes(data->grp->order) -
+ BN_num_bytes(data->my_scalar);
+ BN_bn2bin(data->my_scalar, cruft + offset);
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
/* ciphersuite */
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index e149ee3..0bb9d14 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -94,9 +94,9 @@ u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
os_memcpy(rnd + keys.client_random_len, keys.server_random,
keys.server_random_len);
- if (tls_prf(keys.master_key, keys.master_key_len,
- label, rnd, keys.client_random_len +
- keys.server_random_len, out, len))
+ if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+ label, rnd, keys.client_random_len +
+ keys.server_random_len, out, len))
goto fail;
os_free(rnd);
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 702c50c..398d0f1 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,16 +24,7 @@
#include "eap_common/eap_ttls.h"
-/* Maximum supported TTLS version
- * 0 = RFC 5281
- * 1 = draft-funk-eap-ttls-v1-00.txt
- */
-#ifndef EAP_TTLS_VERSION
-#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
-#endif /* EAP_TTLS_VERSION */
-
-
-#define MSCHAPV2_KEY_LEN 16
+#define EAP_TTLS_VERSION 0
static void eap_ttls_reset(struct eap_sm *sm, void *priv);
@@ -43,17 +34,15 @@ struct eap_ttls_data {
struct eap_ssl_data ssl;
enum {
START, PHASE1, PHASE2_START, PHASE2_METHOD,
- PHASE2_MSCHAPV2_RESP, PHASE_FINISHED, SUCCESS, FAILURE
+ PHASE2_MSCHAPV2_RESP, SUCCESS, FAILURE
} state;
int ttls_version;
- int force_version;
const struct eap_method *phase2_method;
void *phase2_priv;
int mschapv2_resp_ok;
u8 mschapv2_auth_response[20];
u8 mschapv2_ident;
- int tls_ia_configured;
struct wpabuf *pending_phase2_eap_resp;
int tnc_started;
};
@@ -72,8 +61,6 @@ static const char * eap_ttls_state_txt(int state)
return "PHASE2_METHOD";
case PHASE2_MSCHAPV2_RESP:
return "PHASE2_MSCHAPV2_RESP";
- case PHASE_FINISHED:
- return "PHASE_FINISHED";
case SUCCESS:
return "SUCCESS";
case FAILURE:
@@ -111,7 +98,8 @@ static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
}
avp->avp_code = host_to_be32(avp_code);
- avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len));
+ avp->avp_length = host_to_be32(((u32) flags << 24) |
+ ((u32) (hdrlen + len)));
return avphdr + hdrlen;
}
@@ -320,54 +308,8 @@ fail:
static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
struct eap_ttls_data *data, size_t len)
{
- struct tls_keys keys;
- u8 *challenge, *rnd;
-
- if (data->ttls_version == 0) {
- return eap_server_tls_derive_key(sm, &data->ssl,
- "ttls challenge", len);
- }
-
- os_memset(&keys, 0, sizeof(keys));
- if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
- keys.client_random == NULL || keys.server_random == NULL ||
- keys.inner_secret == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
- "client random, or server random to derive "
- "implicit challenge");
- return NULL;
- }
-
- rnd = os_malloc(keys.client_random_len + keys.server_random_len);
- challenge = os_malloc(len);
- if (rnd == NULL || challenge == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
- "challenge derivation");
- os_free(rnd);
- os_free(challenge);
- return NULL;
- }
- os_memcpy(rnd, keys.server_random, keys.server_random_len);
- os_memcpy(rnd + keys.server_random_len, keys.client_random,
- keys.client_random_len);
-
- if (tls_prf(keys.inner_secret, keys.inner_secret_len,
- "inner application challenge", rnd,
- keys.client_random_len + keys.server_random_len,
- challenge, len)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
- "challenge");
- os_free(rnd);
- os_free(challenge);
- return NULL;
- }
-
- os_free(rnd);
-
- wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
- challenge, len);
-
- return challenge;
+ return eap_server_tls_derive_key(sm, &data->ssl, "ttls challenge",
+ len);
}
@@ -379,27 +321,8 @@ static void * eap_ttls_init(struct eap_sm *sm)
if (data == NULL)
return NULL;
data->ttls_version = EAP_TTLS_VERSION;
- data->force_version = -1;
- if (sm->user && sm->user->force_version >= 0) {
- data->force_version = sm->user->force_version;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: forcing version %d",
- data->force_version);
- data->ttls_version = data->force_version;
- }
data->state = START;
- if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
- data->ttls_version > 0) {
- if (data->force_version > 0) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
- "TLS library does not support TLS/IA.",
- data->force_version);
- eap_ttls_reset(sm, data);
- return NULL;
- }
- data->ttls_version = 0;
- }
-
if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
eap_ttls_reset(sm, data);
@@ -516,14 +439,6 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2(
}
-static struct wpabuf * eap_ttls_build_phase_finished(
- struct eap_sm *sm, struct eap_ttls_data *data, int final)
-{
- return tls_connection_ia_send_phase_finished(sm->ssl_ctx,
- data->ssl.conn, final);
-}
-
-
static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
{
struct eap_ttls_data *data = priv;
@@ -559,11 +474,6 @@ static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
data->ssl.tls_out_pos = 0;
data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data);
break;
- case PHASE_FINISHED:
- wpabuf_free(data->ssl.tls_out);
- data->ssl.tls_out_pos = 0;
- data->ssl.tls_out = eap_ttls_build_phase_finished(sm, data, 1);
- break;
default:
wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
__func__, data->state);
@@ -591,37 +501,6 @@ static Boolean eap_ttls_check(struct eap_sm *sm, void *priv,
}
-static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
- struct eap_ttls_data *data,
- const u8 *key, size_t key_len)
-{
- u8 *buf;
- size_t buf_len;
- int ret;
-
- if (key) {
- buf_len = 2 + key_len;
- buf = os_malloc(buf_len);
- if (buf == NULL)
- return -1;
- WPA_PUT_BE16(buf, key_len);
- os_memcpy(buf + 2, key, key_len);
- } else {
- buf = NULL;
- buf_len = 0;
- }
-
- wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
- "secret permutation", buf, buf_len);
- ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
- data->ssl.conn,
- buf, buf_len);
- os_free(buf);
-
- return ret;
-}
-
-
static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
struct eap_ttls_data *data,
const u8 *user_password,
@@ -644,8 +523,7 @@ static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
}
wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password");
- eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
- SUCCESS);
+ eap_ttls_state(data, SUCCESS);
}
@@ -701,8 +579,7 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
- eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
- SUCCESS);
+ eap_ttls_state(data, SUCCESS);
} else {
wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password");
eap_ttls_state(data, FAILURE);
@@ -762,8 +639,7 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
- eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
- SUCCESS);
+ eap_ttls_state(data, SUCCESS);
} else {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response");
wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received",
@@ -863,30 +739,6 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
"NT-Response");
data->mschapv2_resp_ok = 1;
- if (data->ttls_version > 0) {
- const u8 *pw_hash;
- u8 pw_hash_buf[16], pw_hash_hash[16], master_key[16];
- u8 session_key[2 * MSCHAPV2_KEY_LEN];
-
- if (sm->user->password_hash)
- pw_hash = sm->user->password;
- else {
- nt_password_hash(sm->user->password,
- sm->user->password_len,
- pw_hash_buf);
- pw_hash = pw_hash_buf;
- }
- hash_nt_password_hash(pw_hash, pw_hash_hash);
- get_master_key(pw_hash_hash, nt_response, master_key);
- get_asymetric_start_key(master_key, session_key,
- MSCHAPV2_KEY_LEN, 0, 0);
- get_asymetric_start_key(master_key,
- session_key + MSCHAPV2_KEY_LEN,
- MSCHAPV2_KEY_LEN, 1, 0);
- eap_ttls_ia_permute_inner_secret(sm, data,
- session_key,
- sizeof(session_key));
- }
if (sm->user->password_hash) {
generate_authenticator_response_pwhash(
@@ -1030,17 +882,7 @@ static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm,
}
break;
case PHASE2_METHOD:
- if (data->ttls_version > 0) {
- if (m->getKey) {
- u8 *key;
- size_t key_len;
- key = m->getKey(sm, priv, &key_len);
- eap_ttls_ia_permute_inner_secret(sm, data,
- key, key_len);
- }
- eap_ttls_state(data, PHASE_FINISHED);
- } else
- eap_ttls_state(data, SUCCESS);
+ eap_ttls_state(data, SUCCESS);
break;
case FAILURE:
break;
@@ -1130,23 +972,6 @@ static void eap_ttls_process_phase2(struct eap_sm *sm,
return;
}
- if (data->state == PHASE_FINISHED) {
- if (wpabuf_len(in_decrypted) == 0 &&
- tls_connection_ia_final_phase_finished(sm->ssl_ctx,
- data->ssl.conn)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished "
- "received");
- eap_ttls_state(data, SUCCESS);
- } else {
- wpa_printf(MSG_INFO, "EAP-TTLS: Did not receive valid "
- "FinalPhaseFinished");
- eap_ttls_state(data, FAILURE);
- }
-
- wpabuf_free(in_decrypted);
- return;
- }
-
wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP",
in_decrypted);
@@ -1245,15 +1070,6 @@ static int eap_ttls_process_version(struct eap_sm *sm, void *priv,
data->ttls_version = peer_version;
}
- if (data->ttls_version > 0 && !data->tls_ia_configured) {
- if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable "
- "TLS/IA");
- return -1;
- }
- data->tls_ia_configured = 1;
- }
-
return 0;
}
@@ -1270,7 +1086,6 @@ static void eap_ttls_process_msg(struct eap_sm *sm, void *priv,
break;
case PHASE2_START:
case PHASE2_METHOD:
- case PHASE_FINISHED:
eap_ttls_process_phase2(sm, data, data->ssl.tls_in);
eap_ttls_start_tnc(sm, data);
break;
@@ -1279,8 +1094,7 @@ static void eap_ttls_process_msg(struct eap_sm *sm, void *priv,
0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
"acknowledged response");
- eap_ttls_state(data, data->ttls_version > 0 ?
- PHASE_FINISHED : SUCCESS);
+ eap_ttls_state(data, SUCCESS);
} else if (!data->mschapv2_resp_ok) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
"acknowledged error");
@@ -1321,54 +1135,6 @@ static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv)
}
-static u8 * eap_ttls_v1_derive_key(struct eap_sm *sm,
- struct eap_ttls_data *data)
-{
- struct tls_keys keys;
- u8 *rnd, *key;
-
- os_memset(&keys, 0, sizeof(keys));
- if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
- keys.client_random == NULL || keys.server_random == NULL ||
- keys.inner_secret == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
- "client random, or server random to derive keying "
- "material");
- return NULL;
- }
-
- rnd = os_malloc(keys.client_random_len + keys.server_random_len);
- key = os_malloc(EAP_TLS_KEY_LEN);
- if (rnd == NULL || key == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
- os_free(rnd);
- os_free(key);
- return NULL;
- }
- os_memcpy(rnd, keys.client_random, keys.client_random_len);
- os_memcpy(rnd + keys.client_random_len, keys.server_random,
- keys.server_random_len);
-
- if (tls_prf(keys.inner_secret, keys.inner_secret_len,
- "ttls v1 keying material", rnd, keys.client_random_len +
- keys.server_random_len, key, EAP_TLS_KEY_LEN)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
- os_free(rnd);
- os_free(key);
- return NULL;
- }
-
- wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
- rnd, keys.client_random_len + keys.server_random_len);
- wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
- keys.inner_secret, keys.inner_secret_len);
-
- os_free(rnd);
-
- return key;
-}
-
-
static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_ttls_data *data = priv;
@@ -1377,14 +1143,9 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- if (data->ttls_version == 0) {
- eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "ttls keying material",
- EAP_TLS_KEY_LEN);
- } else {
- eapKeyData = eap_ttls_v1_derive_key(sm, data);
- }
-
+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+ "ttls keying material",
+ EAP_TLS_KEY_LEN);
if (eapKeyData) {
*len = EAP_TLS_KEY_LEN;
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
diff --git a/src/eap_server/ikev2.c b/src/eap_server/ikev2.c
index 9624d53..f5bbb14 100644
--- a/src/eap_server/ikev2.c
+++ b/src/eap_server/ikev2.c
@@ -404,7 +404,7 @@ static int ikev2_process_ker(struct ikev2_initiator_data *data,
}
/* RFC 4306, Section 3.4:
- * The length of DH public value MUST be equal to the lenght of the
+ * The length of DH public value MUST be equal to the length of the
* prime modulus.
*/
if (ker_len - 4 != data->dh->prime_len) {
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 4aa71ad..e600954 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -1017,7 +1017,7 @@ static struct eapol_callbacks eapol_cb =
int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
{
- if (sm == NULL || ctx != sm->eap)
+ if (sm == NULL || ctx == NULL || ctx != sm->eap)
return -1;
eap_sm_pending_cb(sm->eap);
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index bb6cff6..ffc6619 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -561,7 +561,7 @@ SM_STEP(SUPP_BE)
* IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
* and SUCCESS based on eapFail and eapSuccess, respectively.
* However, IEEE Std 802.1X-2004 is also specifying that
- * eapNoResp should be set in conjuction with eapSuccess and
+ * eapNoResp should be set in conjunction with eapSuccess and
* eapFail which would mean that more than one of the
* transitions here would be activated at the same time.
* Skipping RESPONSE and/or RECEIVE states in these cases can
@@ -1813,7 +1813,7 @@ static void eapol_sm_notify_pending(void *ctx)
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-static void eapol_sm_eap_param_needed(void *ctx, const char *field,
+static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
const char *txt)
{
struct eapol_sm *sm = ctx;
@@ -1883,6 +1883,7 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
conf.pkcs11_module_path = ctx->pkcs11_module_path;
conf.wps = ctx->wps;
+ conf.cert_in_cb = ctx->cert_in_cb;
sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
if (sm->eap == NULL) {
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 3ea7e79..bcb00b5 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -208,10 +208,10 @@ struct eapol_ctx {
/**
* eap_param_needed - Notify that EAP parameter is needed
* @ctx: Callback context (ctx)
- * @field: Field name (e.g., "IDENTITY")
+ * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
* @txt: User readable text describing the required parameter
*/
- void (*eap_param_needed)(void *ctx, const char *field,
+ void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
const char *txt);
/**
@@ -231,6 +231,11 @@ struct eapol_ctx {
*/
void (*cert_cb)(void *ctx, int depth, const char *subject,
const char *cert_hash, const struct wpabuf *cert);
+
+ /**
+ * cert_in_cb - Include server certificates in callback
+ */
+ int cert_in_cb;
};
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index bef3926..8c768f6 100644..100755
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -17,6 +17,9 @@
#include "common.h"
#include "eloop.h"
#include "common/ieee802_11_defs.h"
+#ifdef ANDROID_P2P
+#include "common/wpa_ctrl.h"
+#endif
#include "common/ieee802_11_common.h"
#include "wps/wps_i.h"
#include "p2p_i.h"
@@ -106,12 +109,42 @@ static const char * p2p_state_txt(int state)
return "INVITE";
case P2P_INVITE_LISTEN:
return "INVITE_LISTEN";
+ case P2P_SEARCH_WHEN_READY:
+ return "SEARCH_WHEN_READY";
default:
return "?";
}
}
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
+{
+ struct p2p_device *dev = NULL;
+
+ if (!addr || !p2p)
+ return 0;
+
+ dev = p2p_get_device(p2p, addr);
+ if (dev)
+ return dev->wps_prov_info;
+ else
+ return 0;
+}
+
+
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr)
+{
+ struct p2p_device *dev = NULL;
+
+ if (!iface_addr || !p2p)
+ return;
+
+ dev = p2p_get_device_interface(p2p, iface_addr);
+ if (dev)
+ dev->wps_prov_info = 0;
+}
+
+
void p2p_set_state(struct p2p_data *p2p, int new_state)
{
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
@@ -144,6 +177,8 @@ void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
struct p2p_go_neg_results res;
p2p_clear_timeout(p2p);
p2p_set_state(p2p, P2P_IDLE);
+ if (p2p->go_neg_peer)
+ p2p->go_neg_peer->wps_method = WPS_NOT_READY;
p2p->go_neg_peer = NULL;
os_memset(&res, 0, sizeof(res));
@@ -219,6 +254,12 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
p2p->pending_listen_usec = (timeout % 1000) * 1000;
if (p2p->p2p_scan_running) {
+ if (p2p->start_after_scan == P2P_AFTER_SCAN_NOTHING) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: p2p_scan running - connect is already "
+ "pending - skip listen");
+ return 0;
+ }
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: p2p_scan running - delay start of listen state");
p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN;
@@ -363,7 +404,7 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
* group, the information will be restored in the loop following this.
*/
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
- if (os_memcpy(dev->member_in_go_iface, go_interface_addr,
+ if (os_memcmp(dev->member_in_go_iface, go_interface_addr,
ETH_ALEN) == 0) {
os_memset(dev->member_in_go_iface, 0, ETH_ALEN);
os_memset(dev->member_in_go_dev, 0, ETH_ALEN);
@@ -372,6 +413,9 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
for (c = 0; c < info.num_clients; c++) {
struct p2p_client_info *cli = &info.client[c];
+ if (os_memcmp(cli->p2p_device_addr, p2p->cfg->dev_addr,
+ ETH_ALEN) == 0)
+ continue; /* ignore our own entry */
dev = p2p_get_device(p2p, cli->p2p_device_addr);
if (dev) {
/*
@@ -574,11 +618,6 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
freq, msg.ds_params ? *msg.ds_params : -1);
}
dev->listen_freq = freq;
-#ifdef ANDROID_BRCM_P2P_PATCH
- if(msg.group_info)
- dev->go_state = REMOTE_GO;
-#endif
-
if (msg.group_info)
dev->oper_freq = freq;
dev->info.level = level;
@@ -631,9 +670,10 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
int i;
if (p2p->go_neg_peer == dev) {
-#ifdef ANDROID_BRCM_P2P_PATCH
+ /*
+ * If GO Negotiation is in progress, report that it has failed.
+ */
p2p_go_neg_failed(p2p, dev, -1);
-#endif
p2p->go_neg_peer = NULL;
}
if (p2p->invite_peer == dev)
@@ -787,19 +827,18 @@ static int p2p_run_after_scan(struct p2p_data *p2p)
enum p2p_after_scan op;
if (p2p->after_scan_tx) {
- int ret;
/* TODO: schedule p2p_run_after_scan to be called from TX
* status callback(?) */
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send pending "
"Action frame at p2p_scan completion");
- ret = p2p->cfg->send_action(p2p->cfg->cb_ctx,
- p2p->after_scan_tx->freq,
- p2p->after_scan_tx->dst,
- p2p->after_scan_tx->src,
- p2p->after_scan_tx->bssid,
- (u8 *) (p2p->after_scan_tx + 1),
- p2p->after_scan_tx->len,
- p2p->after_scan_tx->wait_time);
+ p2p->cfg->send_action(p2p->cfg->cb_ctx,
+ p2p->after_scan_tx->freq,
+ p2p->after_scan_tx->dst,
+ p2p->after_scan_tx->src,
+ p2p->after_scan_tx->bssid,
+ (u8 *) (p2p->after_scan_tx + 1),
+ p2p->after_scan_tx->len,
+ p2p->after_scan_tx->wait_time);
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
return 1;
@@ -888,6 +927,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
p2p_device_clear_reported(p2p);
p2p_set_state(p2p, P2P_SEARCH);
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+ p2p->last_p2p_find_timeout = timeout;
if (timeout)
eloop_register_timeout(timeout, 0, p2p_find_timeout,
p2p, NULL);
@@ -913,21 +953,47 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
p2p, NULL);
+ } else if (res == 1) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
+ "p2p_scan at this point - will try again after "
+ "previous scan completes");
+ res = 0;
+ p2p_set_state(p2p, P2P_SEARCH_WHEN_READY);
+ eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
} else {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
"p2p_scan");
+ p2p_set_state(p2p, P2P_IDLE);
+ eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
}
return res;
}
+int p2p_other_scan_completed(struct p2p_data *p2p)
+{
+ if (p2p->state != P2P_SEARCH_WHEN_READY)
+ return 0;
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find "
+ "now that previous scan was completed");
+ if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
+ p2p->num_req_dev_types, p2p->req_dev_types) < 0)
+ return 0;
+ return 1;
+}
+
+
void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
{
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
p2p_clear_timeout(p2p);
p2p_set_state(p2p, P2P_IDLE);
+#ifdef ANDROID_P2P
+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+#endif
+
p2p_free_req_dev_types(p2p);
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
p2p->go_neg_peer = NULL;
@@ -938,6 +1004,16 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
"since we are on correct channel for response");
return;
}
+ if (p2p->drv_in_listen) {
+ /*
+ * The driver may not deliver callback to p2p_listen_end()
+ * when the operation gets canceled, so clear the internal
+ * variable that is tracking driver state.
+ */
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear "
+ "drv_in_listen (%d)", p2p->drv_in_listen);
+ p2p->drv_in_listen = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
}
@@ -1027,6 +1103,26 @@ static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq)
}
+static void p2p_set_dev_persistent(struct p2p_device *dev,
+ int persistent_group)
+{
+ switch (persistent_group) {
+ case 0:
+ dev->flags &= ~(P2P_DEV_PREFER_PERSISTENT_GROUP |
+ P2P_DEV_PREFER_PERSISTENT_RECONN);
+ break;
+ case 1:
+ dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
+ dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_RECONN;
+ break;
+ case 2:
+ dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP |
+ P2P_DEV_PREFER_PERSISTENT_RECONN;
+ break;
+ }
+}
+
+
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
@@ -1044,6 +1140,7 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
if (p2p_prepare_channel(p2p, force_freq) < 0)
return -1;
+ p2p->ssid_set = 0;
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1083,10 +1180,7 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
dev->connect_reqs = 0;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
- if (persistent_group)
- dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
- else
- dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP;
+ p2p_set_dev_persistent(dev, persistent_group);
p2p->go_intent = go_intent;
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
@@ -1156,10 +1250,7 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
dev->flags &= ~P2P_DEV_USER_REJECTED;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
- if (persistent_group)
- dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
- else
- dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP;
+ p2p_set_dev_persistent(dev, persistent_group);
p2p->go_intent = go_intent;
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
@@ -1270,8 +1361,12 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
res.wps_method = peer->wps_method;
- if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
- res.persistent_group = 1;
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+ res.persistent_group = 2;
+ else
+ res.persistent_group = 1;
+ }
if (go) {
/* Setup AP mode for WPS provisioning */
@@ -1311,6 +1406,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
p2p_clear_timeout(p2p);
+ p2p->ssid_set = 0;
peer->go_neg_req_sent = 0;
peer->wps_method = WPS_NOT_READY;
@@ -1367,9 +1463,9 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
}
-void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da, const u8 *sa,
- const u8 *bssid, const u8 *data, size_t len,
- int freq)
+static void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da,
+ const u8 *sa, const u8 *bssid, const u8 *data,
+ size_t len, int freq)
{
if (len < 1)
return;
@@ -1514,6 +1610,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
if (dev) {
if (dev->country[0] == 0 && msg.listen_channel)
os_memcpy(dev->country, msg.listen_channel, 3);
+ os_get_time(&dev->last_seen);
p2p_parse_free(&msg);
return; /* already known */
}
@@ -1653,13 +1750,47 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
}
-static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
+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 void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
+ const u8 *dst, const u8 *bssid, const u8 *ie,
size_t ie_len)
{
struct ieee802_11_elems elems;
struct wpabuf *buf;
struct ieee80211_mgmt *resp;
- struct wpabuf *wps;
+ struct p2p_message msg;
struct wpabuf *ies;
if (!p2p->in_listen || !p2p->drv_in_listen) {
@@ -1678,6 +1809,18 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
return;
}
+ if (dst && !is_broadcast_ether_addr(dst) &&
+ os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
+ /* Not sent to the broadcast address or our P2P Device Address
+ */
+ return;
+ }
+
+ if (bssid && !is_broadcast_ether_addr(bssid)) {
+ /* Not sent to the Wildcard BSSID */
+ return;
+ }
+
if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN ||
os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
0) {
@@ -1685,14 +1828,32 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
return;
}
+ if (supp_rates_11b_only(&elems)) {
+ /* Indicates support for 11b rates only */
+ return;
+ }
+
+ os_memset(&msg, 0, sizeof(msg));
+ if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
+ /* Could not parse P2P attributes */
+ return;
+ }
+
+ if (msg.device_id &&
+ os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN != 0)) {
+ /* Device ID did not match */
+ p2p_parse_free(&msg);
+ return;
+ }
+
/* Check Requested Device Type match */
- wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
- if (wps && !p2p_match_dev_type(p2p, wps)) {
- wpabuf_free(wps);
+ if (msg.wps_attributes &&
+ !p2p_match_dev_type(p2p, msg.wps_attributes)) {
/* No match with Requested Device Type */
+ p2p_parse_free(&msg);
return;
}
- wpabuf_free(wps);
+ p2p_parse_free(&msg);
if (!p2p->cfg->send_probe_resp)
return; /* Response generated elsewhere */
@@ -1759,12 +1920,12 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
}
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
- size_t ie_len)
+int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+ const u8 *bssid, const u8 *ie, size_t ie_len)
{
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
- p2p_reply_probe(p2p, addr, ie, ie_len);
+ p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
p2p->go_neg_peer &&
@@ -2221,11 +2382,11 @@ void p2p_continue_find(struct p2p_data *p2p)
} else if (dev->req_config_methods &&
!(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
- "pending Provisioning Discovery Request to "
+ "pending Provision Discovery Request to "
MACSTR " (config methods 0x%x)",
MAC2STR(dev->info.p2p_device_addr),
dev->req_config_methods);
- if (p2p_send_prov_disc_req(p2p, dev, 0) == 0)
+ if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
return;
}
}
@@ -2267,7 +2428,7 @@ static void p2p_sd_cb(struct p2p_data *p2p, int success)
* p2p_retry_pd - Retry any pending provision disc requests in IDLE state
* @p2p: P2P module context from p2p_init()
*/
-void p2p_retry_pd(struct p2p_data *p2p)
+static void p2p_retry_pd(struct p2p_data *p2p)
{
struct p2p_device *dev;
@@ -2290,11 +2451,11 @@ void p2p_retry_pd(struct p2p_data *p2p)
continue;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
- "pending Provisioning Discovery Request to "
+ "pending Provision Discovery Request to "
MACSTR " (config methods 0x%x)",
MAC2STR(dev->info.p2p_device_addr),
dev->req_config_methods);
- p2p_send_prov_disc_req(p2p, dev, 0);
+ p2p_send_prov_disc_req(p2p, dev, 0, 0);
return;
}
}
@@ -2395,6 +2556,12 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies)
}
+size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
+{
+ return 100;
+}
+
+
int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end)
{
return p2p_attr_text(p2p_ie, buf, end);
@@ -2674,15 +2841,7 @@ static void p2p_timeout_wait_peer_connect(struct p2p_data *p2p)
* state once per second to give other uses a chance to use the radio.
*/
p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
-#ifdef ANDROID_BRCM_P2P_PATCH
- /*
- * We need to be back in Listen state soon enough so that we don't miss
- * the GO Nego req from the peer.
- */
- p2p_set_timeout(p2p, 0, 0);
-#else
- p2p_set_timeout(p2p, 1, 0);
-#endif
+ p2p_set_timeout(p2p, 0, 500000);
}
@@ -2862,6 +3021,8 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
case P2P_INVITE_LISTEN:
p2p_timeout_invite_listen(p2p);
break;
+ case P2P_SEARCH_WHEN_READY:
+ break;
}
}
@@ -2884,13 +3045,11 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr)
}
-static const char * p2p_wps_method_text(enum p2p_wps_method method)
+const char * p2p_wps_method_text(enum p2p_wps_method method)
{
switch (method) {
case WPS_NOT_READY:
return "not-ready";
- case WPS_PIN_LABEL:
- return "Label";
case WPS_PIN_DISPLAY:
return "Display";
case WPS_PIN_KEYPAD:
@@ -2918,14 +3077,10 @@ static const char * p2p_go_state_text(enum p2p_go_state go_state)
}
-int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
- char *buf, size_t buflen)
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+ const u8 *addr, int next)
{
struct p2p_device *dev;
- int res;
- char *pos, *end;
- struct os_time now;
- char devtype[WPS_DEV_TYPE_BUFSIZE];
if (addr)
dev = p2p_get_device(p2p, addr);
@@ -2939,35 +3094,37 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
}
if (dev == NULL)
+ return NULL;
+
+ return &dev->info;
+}
+
+
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+ char *buf, size_t buflen)
+{
+ struct p2p_device *dev;
+ int res;
+ char *pos, *end;
+ struct os_time now;
+
+ if (info == NULL)
return -1;
+ dev = (struct p2p_device *) (((u8 *) info) -
+ offsetof(struct p2p_device, info));
+
pos = buf;
end = buf + buflen;
- res = os_snprintf(pos, end - pos, MACSTR "\n",
- MAC2STR(dev->info.p2p_device_addr));
- if (res < 0 || res >= end - pos)
- return pos - buf;
- pos += res;
-
os_get_time(&now);
res = os_snprintf(pos, end - pos,
"age=%d\n"
"listen_freq=%d\n"
- "level=%d\n"
"wps_method=%s\n"
"interface_addr=" MACSTR "\n"
"member_in_go_dev=" MACSTR "\n"
"member_in_go_iface=" MACSTR "\n"
- "pri_dev_type=%s\n"
- "device_name=%s\n"
- "manufacturer=%s\n"
- "model_name=%s\n"
- "model_number=%s\n"
- "serial_number=%s\n"
- "config_methods=0x%x\n"
- "dev_capab=0x%x\n"
- "group_capab=0x%x\n"
"go_neg_req_sent=%d\n"
"go_state=%s\n"
"dialog_token=%u\n"
@@ -2981,21 +3138,10 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
"invitation_reqs=%u\n",
(int) (now.sec - dev->last_seen.sec),
dev->listen_freq,
- dev->info.level,
p2p_wps_method_text(dev->wps_method),
MAC2STR(dev->interface_addr),
MAC2STR(dev->member_in_go_dev),
MAC2STR(dev->member_in_go_iface),
- wps_dev_type_bin2str(dev->info.pri_dev_type,
- devtype, sizeof(devtype)),
- dev->info.device_name,
- dev->info.manufacturer,
- dev->info.model_name,
- dev->info.model_number,
- dev->info.serial_number,
- dev->info.config_methods,
- dev->info.dev_capab,
- dev->info.group_capab,
dev->go_neg_req_sent,
p2p_go_state_text(dev->go_state),
dev->dialog_token,
@@ -3064,6 +3210,12 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
}
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr)
+{
+ return p2p_get_device(p2p, addr) != NULL;
+}
+
+
void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled)
{
if (enabled) {
@@ -3624,3 +3776,20 @@ p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next)
return &dev->info;
}
+
+#ifdef ANDROID_P2P
+int p2p_search_in_progress(struct p2p_data *p2p)
+{
+ if (p2p == NULL)
+ return 0;
+
+ return p2p->state == P2P_SEARCH;
+}
+#endif
+
+int p2p_in_progress(struct p2p_data *p2p)
+{
+ if (p2p == NULL)
+ return 0;
+ return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 72c90b1..05b4a16 100644..100755
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -56,7 +56,7 @@ struct p2p_channels {
};
enum p2p_wps_method {
- WPS_NOT_READY, WPS_PIN_LABEL, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
+ WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
};
/**
@@ -120,6 +120,9 @@ struct p2p_go_neg_results {
/**
* persistent_group - Whether the group should be made persistent
+ * 0 = not persistent
+ * 1 = persistent group without persistent reconnect
+ * 2 = persistent group with persistent reconnect
*/
int persistent_group;
@@ -292,17 +295,6 @@ struct p2p_config {
*/
u8 dev_addr[ETH_ALEN];
-#ifdef ANDROID_BRCM_P2P_PATCH
- /**
- * p2p_dev_addr - P2P Device Address
- *
- * Holds the p2p device address. If the driver uses primary mac address
- * for p2p operations, then this will hold the same value as that of
- * dev_addr.
- */
- u8 p2p_dev_addr[ETH_ALEN];
-#endif
-
/**
* dev_name - Device Name
*/
@@ -602,6 +594,8 @@ struct p2p_config {
* @supp_config_methods: Supported configuration Methods
* @dev_capab: Device Capabilities
* @group_capab: Group Capabilities
+ * @group_id: P2P Group ID (or %NULL if not included)
+ * @group_id_len: Length of P2P Group ID
*
* This callback is used to indicate reception of a Provision Discovery
* Request frame that the P2P module accepted.
@@ -609,7 +603,8 @@ struct p2p_config {
void (*prov_disc_req)(void *ctx, const u8 *peer, u16 config_methods,
const u8 *dev_addr, const u8 *pri_dev_type,
const char *dev_name, u16 supp_config_methods,
- u8 dev_capab, u8 group_capab);
+ u8 dev_capab, u8 group_capab,
+ const u8 *group_id, size_t group_id_len);
/**
* prov_disc_resp - Callback on Provisiong Discovery Response
@@ -857,7 +852,9 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout);
* @go_intent: Local GO intent value (1..15)
* @own_interface_addr: Intended interface address to use with the group
* @force_freq: The only allowed channel frequency in MHz or 0
- * @persistent_group: Whether to create a persistent group
+ * @persistent_group: Whether to create a persistent group (0 = no, 1 =
+ * persistent group without persistent reconnect, 2 = persistent group with
+ * persistent reconnect)
* Returns: 0 on success, -1 on failure
*/
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
@@ -873,7 +870,9 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
* @go_intent: Local GO intent value (1..15)
* @own_interface_addr: Intended interface address to use with the group
* @force_freq: The only allowed channel frequency in MHz or 0
- * @persistent_group: Whether to create a persistent group
+ * @persistent_group: Whether to create a persistent group (0 = no, 1 =
+ * persistent group without persistent reconnect, 2 = persistent group with
+ * persistent reconnect)
* Returns: 0 on success, -1 on failure
*
* This is like p2p_connect(), but the actual group negotiation is not
@@ -898,6 +897,7 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
* @peer_addr: MAC address of the peer P2P client
* @config_methods: WPS Config Methods value (only one bit set)
* @join: Whether this is used by a client joining an active group
+ * @force_freq: Forced TX frequency for the frame (mainly for the join case)
* Returns: 0 on success, -1 on failure
*
* This function can be used to request a discovered P2P peer to display a PIN
@@ -909,7 +909,7 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
* indicated with the p2p_config::prov_disc_resp() callback.
*/
int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
- u16 config_methods, int join);
+ u16 config_methods, int join, int force_freq);
/**
* p2p_sd_request - Schedule a service discovery query
@@ -1039,6 +1039,28 @@ void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr);
*/
void p2p_group_formation_failed(struct p2p_data *p2p);
+/**
+ * p2p_get_provisioning_info - Get any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @addr: Peer P2P Device Address
+ * Returns: WPS provisioning information (WPS config method) or 0 if no
+ * information is available
+ *
+ * This function is used to retrieve stored WPS provisioning info for the given
+ * peer.
+ */
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr);
+
+/**
+ * p2p_clear_provisioning_info - Clear any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @iface_addr: Peer P2P Interface Address
+ *
+ * This function is used to clear stored WPS provisioning info for the given
+ * peer.
+ */
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr);
+
/* Event notifications from lower layer driver operations */
@@ -1046,12 +1068,14 @@ void p2p_group_formation_failed(struct p2p_data *p2p);
* p2p_probe_req_rx - Report reception of a Probe Request frame
* @p2p: P2P module context from p2p_init()
* @addr: Source MAC address
+ * @dst: Destination MAC address if available or %NULL
+ * @bssid: BSSID if available or %NULL
* @ie: Information elements from the Probe Request frame body
* @ie_len: Length of ie buffer in octets
* Returns: 0 to indicate the frame was not processed or 1 if it was
*/
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
- size_t ie_len);
+int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+ const u8 *bssid, const u8 *ie, size_t ie_len);
/**
* p2p_rx_action - Report received Action frame
@@ -1173,6 +1197,9 @@ struct p2p_group;
struct p2p_group_config {
/**
* persistent_group - Whether the group is persistent
+ * 0 = not a persistent group
+ * 1 = persistent group without persistent reconnect
+ * 2 = persistent group with persistent reconnect
*/
int persistent_group;
@@ -1244,16 +1271,6 @@ void p2p_group_deinit(struct p2p_group *group);
*/
int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
const u8 *ie, size_t len);
-#ifdef ANDROID_BRCM_P2P_PATCH
-/**
- * p2p_group_get_dev_addr - Retreive the device address of an assocated P2P
- * client.
- * @group: P2P group context from p2p_group_init()
- * @addr: Interface address of the P2P client
- * Returns: P2P dev_addr on success, NULL on failure
- */
-u8 *p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
-#endif /*ANDROID_BRCM_P2P_PATCH */
/**
* p2p_group_assoc_resp_ie - Build P2P IE for (re)association response
@@ -1363,6 +1380,13 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies);
/**
+ * p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie
+ * @p2p: P2P module context from p2p_init()
+ * Returns: Number of octets that p2p_scan_ie() may add to the buffer
+ */
+size_t p2p_scan_ie_buf_len(struct p2p_data *p2p);
+
+/**
* p2p_go_params - Generate random P2P group parameters
* @p2p: P2P module context from p2p_init()
* @params: Buffer for parameters
@@ -1392,16 +1416,36 @@ int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie);
const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie);
/**
- * p2p_get_peer_info - Get P2P peer information in text format
+ * p2p_get_peer_info - Get P2P peer information
* @p2p: P2P module context from p2p_init()
* @addr: P2P Device Address of the peer or %NULL to indicate the first peer
* @next: Whether to select the peer entry following the one indicated by addr
+ * Returns: Pointer to peer info or %NULL if not found
+ */
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+ const u8 *addr, int next);
+
+/**
+ * p2p_get_peer_info_txt - Get internal P2P peer information in text format
+ * @info: Pointer to P2P peer info from p2p_get_peer_info()
* @buf: Buffer for returning text
* @buflen: Maximum buffer length
* Returns: Number of octets written to the buffer or -1 on failure
+ *
+ * Note: This information is internal to the P2P module and subject to change.
+ * As such, this should not really be used by external programs for purposes
+ * other than debugging.
+ */
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+ char *buf, size_t buflen);
+
+/**
+ * p2p_peer_known - Check whether P2P peer is known
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P Device Address of the peer
+ * Returns: 1 if the specified device is in the P2P peer table or 0 if not
*/
-int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
- char *buf, size_t buflen);
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr);
/**
* p2p_set_client_discoverability - Set client discoverability capability
@@ -1415,7 +1459,7 @@ int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled);
/**
- * p2p_set_manageD_oper - Set managed P2P Device operations capability
+ * p2p_set_managed_oper - Set managed P2P Device operations capability
* @p2p: P2P module context from p2p_init()
* @enabled: Whether managed P2P Device operations will be enabled
*/
@@ -1490,6 +1534,15 @@ unsigned int p2p_get_group_num_members(struct p2p_group *group);
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
/**
+ * p2p_group_get_dev_addr - Get a P2P Device Address of a client in a group
+ * @group: P2P group context from p2p_group_init()
+ * @addr: P2P Interface Address of the client
+ * Returns: P2P Device Address of the client if found or %NULL if no match
+ * found
+ */
+const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
+
+/**
* p2p_get_peer_found - Get P2P peer info structure of a found peer
* @p2p: P2P module context from p2p_init()
* @addr: P2P Device Address of the peer or %NULL to indicate the first peer
@@ -1528,4 +1581,29 @@ int p2p_add_wps_vendor_extension(struct p2p_data *p2p,
int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
int cfg_op_channel);
+/**
+ * p2p_in_progress - Check whether a P2P operation is progress
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ */
+int p2p_in_progress(struct p2p_data *p2p);
+
+#ifdef ANDROID_P2P
+/**
+ * p2p_in_progress - Check whether a P2P SEARCH is in progress
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ */
+int p2p_search_in_progress(struct p2p_data *p2p);
+#endif
+
+/**
+ * p2p_other_scan_completed - Notify completion of non-P2P scan
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation was started
+ */
+int p2p_other_scan_completed(struct p2p_data *p2p);
+
+const char * p2p_wps_method_text(enum p2p_wps_method method);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index d59e54b..a82e16d 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -164,27 +164,20 @@ void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
len = wpabuf_put(buf, 2); /* IE length to be filled */
/* P2P Device address */
-#ifdef ANDROID_BRCM_P2P_PATCH
- /*
- * P2P_ADDR: Supplicant uses primary mac addr for p2p and hence advertises that. To
- * to make it compatible with solution using virtual interface for P2P, a new variable
- * is added to hold the actual p2p device address.
- */
- wpabuf_put_data(buf, p2p->cfg->p2p_dev_addr, ETH_ALEN);
-#else
wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
-#endif
/* Config Methods */
methods = 0;
if (peer && peer->wps_method != WPS_NOT_READY) {
if (peer->wps_method == WPS_PBC)
methods |= WPS_CONFIG_PUSHBUTTON;
- else if (peer->wps_method == WPS_PIN_LABEL)
- methods |= WPS_CONFIG_LABEL;
else if (peer->wps_method == WPS_PIN_DISPLAY ||
peer->wps_method == WPS_PIN_KEYPAD)
methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+ } else if (p2p->cfg->config_methods) {
+ methods |= p2p->cfg->config_methods &
+ (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
+ WPS_CONFIG_KEYPAD);
} else {
methods |= WPS_CONFIG_PUSHBUTTON;
methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index f5937b9..eb85f51 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -107,8 +107,6 @@ static int p2p_peer_channels(struct p2p_data *p2p, struct p2p_device *dev,
static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
{
switch (wps_method) {
- case WPS_PIN_LABEL:
- return DEV_PW_DEFAULT;
case WPS_PIN_DISPLAY:
return DEV_PW_REGISTRAR_SPECIFIED;
case WPS_PIN_KEYPAD:
@@ -124,8 +122,6 @@ static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
static const char * p2p_wps_method_str(enum p2p_wps_method wps_method)
{
switch (wps_method) {
- case WPS_PIN_LABEL:
- return "Label";
case WPS_PIN_DISPLAY:
return "Display";
case WPS_PIN_KEYPAD:
@@ -156,8 +152,11 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
len = p2p_buf_add_ie_hdr(buf);
group_capab = 0;
- if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ }
if (p2p->cross_connect)
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (p2p->cfg->p2p_intra_bss)
@@ -246,8 +245,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
p2p_buf_add_status(buf, status);
group_capab = 0;
if (peer && peer->go_state == LOCAL_GO) {
- if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+ group_capab |=
+ P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ }
if (p2p->cross_connect)
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (p2p->cfg->p2p_intra_bss)
@@ -491,15 +494,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
}
if (dev->go_neg_req_sent &&
-#ifdef ANDROID_BRCM_P2P_PATCH
- /* P2P_ADDR: compare against the p2p device address. The own mac
- address may not not be the actual p2p device address, if you
- are using a virtual interface.
- */
- os_memcmp(sa, p2p->cfg->p2p_dev_addr, ETH_ALEN) > 0) {
-#else
os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) {
-#endif
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Do not reply since peer has higher "
"address and GO Neg Request already sent");
@@ -524,18 +519,6 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
}
switch (msg.dev_password_id) {
- case DEV_PW_DEFAULT:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: PIN from peer Label");
- if (dev->wps_method != WPS_PIN_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
- p2p_wps_method_str(dev->wps_method));
- status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
- goto fail;
- }
- break;
case DEV_PW_REGISTRAR_SPECIFIED:
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: PIN from peer Display");
@@ -551,8 +534,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
case DEV_PW_USER_SPECIFIED:
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Peer entered PIN on Keypad");
- if (dev->wps_method != WPS_PIN_LABEL &&
- dev->wps_method != WPS_PIN_DISPLAY) {
+ if (dev->wps_method != WPS_PIN_DISPLAY) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: We have wps_method=%s -> "
"incompatible",
@@ -606,7 +588,10 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
p2p->op_channel))
p2p_reselect_channel(p2p, &intersection);
- p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ if (!p2p->ssid_set) {
+ p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ p2p->ssid_set = 1;
+ }
}
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
@@ -695,8 +680,12 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
p2p_buf_add_status(buf, status);
group_capab = 0;
if (peer->go_state == LOCAL_GO) {
- if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+ group_capab |=
+ P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ }
if (p2p->cross_connect)
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (p2p->cfg->p2p_intra_bss)
@@ -907,18 +896,6 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
dev->oper_freq = 0;
switch (msg.dev_password_id) {
- case DEV_PW_DEFAULT:
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: PIN from peer Label");
- if (dev->wps_method != WPS_PIN_KEYPAD) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: We have wps_method=%s -> "
- "incompatible",
- p2p_wps_method_str(dev->wps_method));
- status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
- goto fail;
- }
- break;
case DEV_PW_REGISTRAR_SPECIFIED:
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: PIN from peer Display");
@@ -934,8 +911,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
case DEV_PW_USER_SPECIFIED:
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Peer entered PIN on Keypad");
- if (dev->wps_method != WPS_PIN_LABEL &&
- dev->wps_method != WPS_PIN_DISPLAY) {
+ if (dev->wps_method != WPS_PIN_DISPLAY) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: We have wps_method=%s -> "
"incompatible",
@@ -988,7 +964,10 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
p2p->op_channel))
p2p_reselect_channel(p2p, &intersection);
- p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ if (!p2p->ssid_set) {
+ p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ p2p->ssid_set = 1;
+ }
}
p2p_set_state(p2p, P2P_GO_NEG);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 0d05319..59d1507 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -147,8 +147,11 @@ static void p2p_group_add_common_ies(struct p2p_group *group,
dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;
group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
- if (group->cfg->persistent_group)
+ if (group->cfg->persistent_group) {
group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ if (group->cfg->persistent_group == 2)
+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+ }
if (group->p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
if (group->group_formation)
@@ -183,12 +186,7 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
len = p2p_buf_add_ie_hdr(ie);
p2p_group_add_common_ies(group, ie);
-#ifdef ANDROID_BRCM_P2P_PATCH
- /* P2P_ADDR: Use p2p_dev_addr instead of own mac addr*/
- p2p_buf_add_device_id(ie, group->p2p->cfg->p2p_dev_addr);
-#else
p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
-#endif
p2p_group_add_noa(ie, group->noa);
p2p_buf_update_ie_hdr(ie, len);
@@ -315,6 +313,36 @@ static struct wpabuf * p2p_build_client_info(const u8 *addr,
}
+static int p2p_group_remove_member(struct p2p_group *group, const u8 *addr)
+{
+ struct p2p_group_member *m, *prev;
+
+ if (group == NULL)
+ return 0;
+
+ m = group->members;
+ prev = NULL;
+ while (m) {
+ if (os_memcmp(m->addr, addr, ETH_ALEN) == 0)
+ break;
+ prev = m;
+ m = m->next;
+ }
+
+ if (m == NULL)
+ return 0;
+
+ if (prev)
+ prev->next = m->next;
+ else
+ group->members = m->next;
+ p2p_group_free_member(m);
+ group->num_members--;
+
+ return 1;
+}
+
+
int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
const u8 *ie, size_t len)
{
@@ -334,6 +362,8 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
m->dev_addr);
}
+ p2p_group_remove_member(group, addr);
+
m->next = group->members;
group->members = m;
group->num_members++;
@@ -376,27 +406,7 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr)
{
- struct p2p_group_member *m, *prev;
-
- if (group == NULL)
- return;
-
- m = group->members;
- prev = NULL;
- while (m) {
- if (os_memcmp(m->addr, addr, ETH_ALEN) == 0)
- break;
- prev = m;
- m = m->next;
- }
-
- if (m) {
- if (prev)
- prev->next = m->next;
- else
- group->members = m->next;
- p2p_group_free_member(m);
- group->num_members--;
+ if (p2p_group_remove_member(group, addr)) {
wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove "
"client " MACSTR " from group; num_members=%u/%u",
MAC2STR(addr), group->num_members,
@@ -499,11 +509,7 @@ int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa,
} else {
if (group->noa) {
if (wpabuf_size(group->noa) >= noa_len) {
- #ifdef ANDROID_BRCM_P2P_PATCH
group->noa->used = 0;
- #else
- group->noa->size = 0;
- #endif
wpabuf_put_data(group->noa, noa, noa_len);
} else {
wpabuf_free(group->noa);
@@ -551,19 +557,19 @@ static struct p2p_group_member * p2p_group_get_client_iface(
return NULL;
}
-#ifdef ANDROID_BRCM_P2P_PATCH
-u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr)
+
+const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr)
{
struct p2p_group_member *m;
+ if (group == NULL)
+ return NULL;
m = p2p_group_get_client_iface(group, addr);
-
- if (m)
+ if (m && !is_zero_ether_addr(m->dev_addr))
return m->dev_addr;
- else
- return NULL;
+ return NULL;
}
-#endif /* ANDROID_BRCM_P2P_PATCH */
+
static struct wpabuf * p2p_build_go_disc_req(void)
{
@@ -662,11 +668,11 @@ u8 p2p_group_presence_req(struct p2p_group *group,
else
wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa,
curr_noa_len);
-#ifndef ANDROID_BRCM_P2P_PATCH
+
/* TODO: properly process request and store copy */
- if (curr_noa_len > 0)
+ if (curr_noa_len > 0 || curr_noa_len == -1)
return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
-#endif
+
return P2P_SC_SUCCESS;
}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index afb891e..0dc33e7 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -18,8 +18,6 @@
#include "utils/list.h"
#include "p2p.h"
-/* TODO: add removal of expired P2P device entries */
-
enum p2p_go_state {
UNKNOWN_GO,
LOCAL_GO,
@@ -69,10 +67,18 @@ struct p2p_device {
size_t oper_ssid_len;
/**
- * req_config_methods - Pending provisioning discovery methods
+ * req_config_methods - Pending provision discovery methods
*/
u16 req_config_methods;
+ /**
+ * wps_prov_info - Stored provisioning WPS config method
+ *
+ * This is used to store pending WPS config method between Provisioning
+ * Discovery and connection to a running group.
+ */
+ u16 wps_prov_info;
+
#define P2P_DEV_PROBE_REQ_ONLY BIT(0)
#define P2P_DEV_REPORTED BIT(1)
#define P2P_DEV_NOT_YET_READY BIT(2)
@@ -89,6 +95,7 @@ struct p2p_device {
#define P2P_DEV_FORCE_FREQ BIT(13)
#define P2P_DEV_PD_FOR_JOIN BIT(14)
#define P2P_DEV_REPORTED_ONCE BIT(15)
+#define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
unsigned int flags;
int status; /* enum p2p_status_code */
@@ -200,6 +207,11 @@ struct p2p_data {
* P2P_INVITE_LISTEN - Listen during Invite
*/
P2P_INVITE_LISTEN,
+
+ /**
+ * P2P_SEARCH_WHEN_READY - Waiting to start Search
+ */
+ P2P_SEARCH_WHEN_READY,
} state;
/**
@@ -273,6 +285,11 @@ struct p2p_data {
size_t ssid_len;
/**
+ * ssid_set - Whether SSID is already set for GO Negotiation
+ */
+ int ssid_set;
+
+ /**
* Regulatory class for own operational channel
*/
u8 op_reg_class;
@@ -349,6 +366,7 @@ struct p2p_data {
int inv_persistent;
enum p2p_discovery_type find_type;
+ unsigned int last_p2p_find_timeout;
u8 last_prog_scan_class;
u8 last_prog_scan_chan;
int p2p_scan_running;
@@ -532,11 +550,6 @@ struct p2p_noa_desc {
/* p2p_group.c */
const u8 * p2p_group_get_interface_addr(struct p2p_group *group);
-
-#ifdef ANDROID_BRCM_P2P_PATCH
-void p2p_get_group_noa(struct p2p_group *group, u8 *noa, size_t* noa_len);
-#endif
-
u8 p2p_group_presence_req(struct p2p_group *group,
const u8 *client_interface_addr,
const u8 *noa, size_t noa_len);
@@ -606,7 +619,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len);
int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
- int join);
+ int join, int force_freq);
void p2p_reset_pending_pd(struct p2p_data *p2p);
/* p2p_invitation.c */
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 42015ad..bb2767d 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -55,11 +55,7 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT)
dev_addr = peer->info.p2p_device_addr;
else
-#ifdef ANDROID_BRCM_P2P_PATCH
- dev_addr = p2p->cfg->p2p_dev_addr;
-#else
dev_addr = p2p->cfg->dev_addr;
-#endif
p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len);
p2p_buf_add_device_info(buf, p2p, peer);
p2p_buf_update_ie_hdr(buf, len);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 32d82f6..1ee59c5 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -112,7 +112,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
MAC2STR(sa), msg.wps_config_methods, rx_freq);
dev = p2p_get_device(p2p, sa);
- if (dev == NULL || !(dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
+ if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Provision Discovery Request from "
"unknown peer " MACSTR, MAC2STR(sa));
@@ -191,8 +191,8 @@ out:
msg.device_name, msg.config_methods,
msg.capability ? msg.capability[0] : 0,
msg.capability ? msg.capability[1] :
- 0);
-
+ 0,
+ msg.group_id, msg.group_id_len);
}
p2p_parse_free(&msg);
}
@@ -209,14 +209,14 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
return;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Received Provisioning Discovery Response from " MACSTR
+ "P2P: Received Provision Discovery Response from " MACSTR
" with config methods 0x%x",
MAC2STR(sa), msg.wps_config_methods);
dev = p2p_get_device(p2p, sa);
if (dev == NULL || !dev->req_config_methods) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore Provisioning Discovery Response from "
+ "P2P: Ignore Provision Discovery Response from "
MACSTR " with no pending request", MAC2STR(sa));
p2p_parse_free(&msg);
return;
@@ -229,7 +229,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
if (dev->dialog_token != msg.dialog_token) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Ignore Provisioning Discovery Response with "
+ "P2P: Ignore Provision Discovery Response with "
"unexpected Dialog Token %u (expected %u)",
msg.dialog_token, dev->dialog_token);
p2p_parse_free(&msg);
@@ -246,7 +246,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
if (msg.wps_config_methods != dev->req_config_methods) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
- "our Provisioning Discovery Request");
+ "our Provision Discovery Request");
if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
P2P_PROV_DISC_REJECTED);
@@ -267,6 +267,10 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
}
+
+ /* Store the provisioning info */
+ dev->wps_prov_info = msg.wps_config_methods;
+
p2p_parse_free(&msg);
out:
@@ -279,25 +283,16 @@ out:
int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
- int join)
+ int join, int force_freq)
{
struct wpabuf *req;
int freq;
-#ifdef ANDROID_BRCM_P2P_PATCH
- if(dev->go_state == REMOTE_GO) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: GO Sending it to oper_freq %d", dev->oper_freq);
- freq= dev->oper_freq;
- }
- else {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: NOT GO oper_freq %d listen_freq %d", dev->oper_freq, dev->listen_freq);
- freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
- }
-#else
- freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
-#endif
+ if (force_freq > 0)
+ freq = force_freq;
+ else
+ freq = dev->listen_freq > 0 ? dev->listen_freq :
+ dev->oper_freq;
if (freq <= 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: No Listen/Operating frequency known for the "
@@ -345,7 +340,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
- u16 config_methods, int join)
+ u16 config_methods, int join, int force_freq)
{
struct p2p_device *dev;
@@ -365,6 +360,9 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
if (config_methods == 0)
return -1;
+ /* Reset provisioning info */
+ dev->wps_prov_info = 0;
+
dev->req_config_methods = config_methods;
if (join)
dev->flags |= P2P_DEV_PD_FOR_JOIN;
@@ -391,12 +389,26 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
- return p2p_send_prov_disc_req(p2p, dev, join);
+ return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
}
void p2p_reset_pending_pd(struct p2p_data *p2p)
{
+ struct p2p_device *dev;
+
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (os_memcmp(p2p->pending_pd_devaddr,
+ dev->info.p2p_device_addr, ETH_ALEN))
+ continue;
+ if (!dev->req_config_methods)
+ continue;
+ if (dev->flags & P2P_DEV_PD_FOR_JOIN)
+ continue;
+ /* Reset the config methods of the device */
+ dev->req_config_methods = 0;
+ }
+
p2p->user_initiated_pd = 0;
os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
p2p->pd_retries = 0;
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 9e26873..f53d4b5 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -16,6 +16,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -26,7 +27,7 @@ struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
struct p2p_sd_query *q;
if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
- return 0; /* peer does not support SD */
+ return NULL; /* peer does not support SD */
for (q = p2p->sd_queries; q; q = q->next) {
if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
@@ -90,51 +91,21 @@ static struct wpabuf * p2p_build_sd_query(u16 update_indic,
struct wpabuf *tlvs)
{
struct wpabuf *buf;
- u8 *len_pos, *len_pos2;
+ u8 *len_pos;
- buf = wpabuf_alloc(1000 + wpabuf_len(tlvs));
+ buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs));
if (buf == NULL)
return NULL;
- wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
- wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
- wpabuf_put_u8(buf, 0); /* Dialog Token */
-
- /* Advertisement Protocol IE */
- wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
- wpabuf_put_u8(buf, 2); /* Length */
- wpabuf_put_u8(buf, 0); /* QueryRespLenLimit | PAME-BI */
- wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
- /* Query Request */
- len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
- /* NQP Query Request Frame */
- wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
- len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
+ /* ANQP Query Request Frame */
+ len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
wpabuf_put_be24(buf, OUI_WFA);
wpabuf_put_u8(buf, P2P_OUI_TYPE);
wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
wpabuf_put_buf(buf, tlvs);
+ gas_anqp_set_element_len(buf, len_pos);
- WPA_PUT_LE16(len_pos2, (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
- WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
-
- return buf;
-}
-
-
-static struct wpabuf * p2p_build_gas_comeback_req(u8 dialog_token)
-{
- struct wpabuf *buf;
-
- buf = wpabuf_alloc(3);
- if (buf == NULL)
- return NULL;
-
- wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
- wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_REQ);
- wpabuf_put_u8(buf, dialog_token);
+ gas_anqp_set_len(buf);
return buf;
}
@@ -145,7 +116,7 @@ static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst,
{
struct wpabuf *req;
- req = p2p_build_gas_comeback_req(dialog_token);
+ req = gas_build_comeback_req(dialog_token);
if (req == NULL)
return;
@@ -165,42 +136,26 @@ static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code,
const struct wpabuf *tlvs)
{
struct wpabuf *buf;
- u8 *len_pos, *len_pos2;
+ u8 *len_pos;
- buf = wpabuf_alloc(1000 + (tlvs ? wpabuf_len(tlvs) : 0));
+ buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+ comeback_delay,
+ 100 + (tlvs ? wpabuf_len(tlvs) : 0));
if (buf == NULL)
return NULL;
- wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
- wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
- wpabuf_put_u8(buf, dialog_token);
- wpabuf_put_le16(buf, status_code);
- wpabuf_put_le16(buf, comeback_delay);
-
- /* Advertisement Protocol IE */
- wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
- wpabuf_put_u8(buf, 2); /* Length */
- wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
- wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
- /* Query Response */
- len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
if (tlvs) {
- /* NQP Query Response Frame */
- wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
- len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
+ /* ANQP Query Response Frame */
+ len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
wpabuf_put_be24(buf, OUI_WFA);
wpabuf_put_u8(buf, P2P_OUI_TYPE);
/* Service Update Indicator */
wpabuf_put_le16(buf, update_indic);
wpabuf_put_buf(buf, tlvs);
-
- WPA_PUT_LE16(len_pos2,
- (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
+ gas_anqp_set_element_len(buf, len_pos);
}
- WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+ gas_anqp_set_len(buf);
return buf;
}
@@ -214,31 +169,15 @@ static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
u16 total_len)
{
struct wpabuf *buf;
- u8 *len_pos;
- buf = wpabuf_alloc(1000 + len);
+ buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+ more, 0, 100 + len);
if (buf == NULL)
return NULL;
- wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
- wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_RESP);
- wpabuf_put_u8(buf, dialog_token);
- wpabuf_put_le16(buf, status_code);
- wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
- wpabuf_put_le16(buf, 0); /* Comeback Delay */
-
- /* Advertisement Protocol IE */
- wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
- wpabuf_put_u8(buf, 2); /* Length */
- wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
- wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
- /* Query Response */
- len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
if (frag_id == 0) {
- /* NQP Query Response Frame */
- wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
+ /* ANQP Query Response Frame */
+ wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
wpabuf_put_le16(buf, 3 + 1 + 2 + total_len);
wpabuf_put_be24(buf, OUI_WFA);
wpabuf_put_u8(buf, P2P_OUI_TYPE);
@@ -247,8 +186,7 @@ static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
}
wpabuf_put_data(buf, data, len);
-
- WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+ gas_anqp_set_len(buf);
return buf;
}
@@ -349,7 +287,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
- if (*pos != NATIVE_QUERY_PROTOCOL) {
+ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Unsupported GAS advertisement protocol id %u",
*pos);
@@ -366,12 +304,12 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
return;
end = pos + slen;
- /* NQP Query Request */
+ /* ANQP Query Request */
if (pos + 4 > end)
return;
- if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+ if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+ "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
return;
}
pos += 2;
@@ -380,20 +318,20 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
pos += 2;
if (pos + slen > end || slen < 3 + 1) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid NQP Query Request length");
+ "P2P: Invalid ANQP Query Request length");
return;
}
if (WPA_GET_BE24(pos) != OUI_WFA) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+ "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
return;
}
pos += 3;
if (*pos != P2P_OUI_TYPE) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP vendor type %u", *pos);
+ "P2P: Unsupported ANQP vendor type %u", *pos);
return;
}
pos++;
@@ -451,11 +389,7 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
- #ifdef ANDROID_BRCM_P2P_PATCH
- p2p->cfg->p2p_dev_addr,
- #else
p2p->cfg->dev_addr,
- #endif
wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Failed to send Action frame");
@@ -529,7 +463,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
- if (*pos != NATIVE_QUERY_PROTOCOL) {
+ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Unsupported GAS advertisement protocol id %u",
*pos);
@@ -567,12 +501,12 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
return;
}
- /* NQP Query Response */
+ /* ANQP Query Response */
if (pos + 4 > end)
return;
- if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+ if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+ "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
return;
}
pos += 2;
@@ -581,20 +515,20 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
pos += 2;
if (pos + slen > end || slen < 3 + 1) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid NQP Query Response length");
+ "P2P: Invalid ANQP Query Response length");
return;
}
if (WPA_GET_BE24(pos) != OUI_WFA) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+ "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
return;
}
pos += 3;
if (*pos != P2P_OUI_TYPE) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP vendor type %u", *pos);
+ "P2P: Unsupported ANQP vendor type %u", *pos);
return;
}
pos++;
@@ -776,7 +710,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
}
pos++; /* skip QueryRespLenLimit and PAME-BI */
- if (*pos != NATIVE_QUERY_PROTOCOL) {
+ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Unsupported GAS advertisement protocol id %u",
*pos);
@@ -808,29 +742,29 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
if (p2p->sd_rx_resp) {
/*
- * NQP header is only included in the first fragment; rest of
+ * ANQP header is only included in the first fragment; rest of
* the fragments start with continue TLVs.
*/
goto skip_nqp_header;
}
- /* NQP Query Response */
+ /* ANQP Query Response */
if (pos + 4 > end)
return;
- if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+ if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+ "P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
return;
}
pos += 2;
slen = WPA_GET_LE16(pos);
pos += 2;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: NQP Query Response "
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: ANQP Query Response "
"length: %u", slen);
if (slen < 3 + 1) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Invalid NQP Query Response length");
+ "P2P: Invalid ANQP Query Response length");
return;
}
if (pos + 4 > end)
@@ -838,14 +772,14 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
if (WPA_GET_BE24(pos) != OUI_WFA) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+ "P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
return;
}
pos += 3;
if (*pos != P2P_OUI_TYPE) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported NQP vendor type %u", *pos);
+ "P2P: Unsupported ANQP vendor type %u", *pos);
return;
}
pos++;
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 70754ef..3ead847 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -218,6 +218,8 @@ static struct radius_attr_type radius_attrs[] =
{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password",
+ RADIUS_ATTR_UNDIST },
{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
@@ -1090,8 +1092,7 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
const u8 *secret, size_t secret_len)
{
u8 buf[128];
- int padlen, i;
- size_t buf_len, pos;
+ size_t padlen, i, buf_len, pos;
const u8 *addr[2];
size_t len[2];
u8 hash[16];
@@ -1103,7 +1104,7 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
buf_len = data_len;
padlen = data_len % 16;
- if (padlen) {
+ if (padlen && data_len < sizeof(buf)) {
padlen = 16 - padlen;
os_memset(buf + data_len, 0, padlen);
buf_len += padlen;
@@ -1276,6 +1277,120 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
}
+/**
+ * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
+ * @msg: Received RADIUS message
+ * @keylen: Length of returned password
+ * @secret: RADIUS shared secret
+ * @secret_len: Length of secret
+ * @sent_msg: Sent RADIUS message
+ * Returns: pointer to password (free with os_free) or %NULL
+ */
+char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
+ const u8 *secret, size_t secret_len,
+ struct radius_msg *sent_msg)
+{
+ u8 *buf = NULL;
+ size_t buflen;
+ const u8 *salt;
+ u8 *str;
+ const u8 *addr[3];
+ size_t len[3];
+ u8 hash[16];
+ u8 *pos;
+ size_t i;
+ struct radius_attr_hdr *attr;
+ const u8 *data;
+ size_t dlen;
+ const u8 *fdata = NULL; /* points to found item */
+ size_t fdlen = -1;
+ char *ret = NULL;
+
+ /* find attribute with lowest tag and check it */
+ for (i = 0; i < msg->attr_used; i++) {
+ attr = radius_get_attr_hdr(msg, i);
+ if (attr == NULL ||
+ attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) {
+ continue;
+ }
+ if (attr->length <= 5)
+ continue;
+ data = (const u8 *) (attr + 1);
+ dlen = attr->length - sizeof(*attr);
+ if (dlen <= 3 || dlen % 16 != 3)
+ continue;
+ if (fdata != NULL && fdata[0] <= data[0])
+ continue;
+
+ fdata = data;
+ fdlen = dlen;
+ }
+ if (fdata == NULL)
+ goto out;
+
+ /* alloc writable memory for decryption */
+ buf = os_malloc(fdlen);
+ if (buf == NULL)
+ goto out;
+ os_memcpy(buf, fdata, fdlen);
+ buflen = fdlen;
+
+ /* init pointers */
+ salt = buf + 1;
+ str = buf + 3;
+
+ /* decrypt blocks */
+ pos = buf + buflen - 16; /* last block */
+ while (pos >= str + 16) { /* all but the first block */
+ addr[0] = secret;
+ len[0] = secret_len;
+ addr[1] = pos - 16;
+ len[1] = 16;
+ md5_vector(2, addr, len, hash);
+
+ for (i = 0; i < 16; i++)
+ pos[i] ^= hash[i];
+
+ pos -= 16;
+ }
+
+ /* decrypt first block */
+ if (str != pos)
+ goto out;
+ addr[0] = secret;
+ len[0] = secret_len;
+ addr[1] = sent_msg->hdr->authenticator;
+ len[1] = 16;
+ addr[2] = salt;
+ len[2] = 2;
+ md5_vector(3, addr, len, hash);
+
+ for (i = 0; i < 16; i++)
+ pos[i] ^= hash[i];
+
+ /* derive plaintext length from first subfield */
+ *keylen = (unsigned char) str[0];
+ if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) {
+ /* decryption error - invalid key length */
+ goto out;
+ }
+ if (*keylen == 0) {
+ /* empty password */
+ goto out;
+ }
+
+ /* copy passphrase into new buffer */
+ ret = os_malloc(*keylen);
+ if (ret)
+ os_memcpy(ret, str + 1, *keylen);
+
+out:
+ /* return new buffer */
+ os_free(buf);
+ return ret;
+}
+
+
void radius_free_class(struct radius_class_data *c)
{
size_t i;
diff --git a/src/radius/radius.h b/src/radius/radius.h
index a3cdac0..e69a047 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -82,6 +82,7 @@ enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_NAS_PORT_TYPE = 61,
RADIUS_ATTR_TUNNEL_TYPE = 64,
RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
+ RADIUS_ATTR_TUNNEL_PASSWORD = 69,
RADIUS_ATTR_CONNECT_INFO = 77,
RADIUS_ATTR_EAP_MESSAGE = 79,
RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
@@ -231,6 +232,9 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
const u8 *secret, size_t secret_len);
int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
int radius_msg_get_vlanid(struct radius_msg *msg);
+char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
+ const u8 *secret, size_t secret_len,
+ struct radius_msg *sent_msg);
static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
u32 value)
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 6f1c3a5..47948bc 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -1,6 +1,6 @@
/*
* RADIUS authentication server
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -292,6 +292,10 @@ struct radius_server_data {
* msg_ctx - Context data for wpa_msg() calls
*/
void *msg_ctx;
+
+#ifdef CONFIG_RADIUS_TEST
+ char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
};
@@ -574,6 +578,24 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
int len;
+#ifdef CONFIG_RADIUS_TEST
+ if (data->dump_msk_file) {
+ FILE *f;
+ char buf[2 * 64 + 1];
+ f = fopen(data->dump_msk_file, "a");
+ if (f) {
+ len = sess->eap_if->eapKeyDataLen;
+ if (len > 64)
+ len = 64;
+ len = wpa_snprintf_hex(
+ buf, sizeof(buf),
+ sess->eap_if->eapKeyData, len);
+ buf[len] = '\0';
+ fprintf(f, "%s\n", buf);
+ fclose(f);
+ }
+ }
+#endif /* CONFIG_RADIUS_TEST */
if (sess->eap_if->eapKeyDataLen > 64) {
len = 32;
} else {
@@ -1277,6 +1299,11 @@ radius_server_init(struct radius_server_conf *conf)
}
}
+#ifdef CONFIG_RADIUS_TEST
+ if (conf->dump_msk_file)
+ data->dump_msk_file = os_strdup(conf->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
+
data->clients = radius_server_read_clients(conf->client_file,
conf->ipv6);
if (data->clients == NULL) {
@@ -1328,6 +1355,9 @@ void radius_server_deinit(struct radius_server_data *data)
os_free(data->eap_fast_a_id);
os_free(data->eap_fast_a_id_info);
os_free(data->eap_req_id_text);
+#ifdef CONFIG_RADIUS_TEST
+ os_free(data->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
os_free(data);
}
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 126e314..8d6e2ab 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -1,6 +1,6 @@
/*
* RADIUS authentication server
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -201,6 +201,10 @@ struct radius_server_conf {
* msg_ctx - Context data for wpa_msg() calls
*/
void *msg_ctx;
+
+#ifdef CONFIG_RADIUS_TEST
+ const char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
};
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index cac8c83..3877efb 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -49,6 +49,7 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry,
int replace)
{
+ wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
pmksa->pmksa_count--;
pmksa->free_cb(entry, pmksa->ctx, replace);
_pmksa_cache_free_entry(entry);
@@ -185,6 +186,14 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
"the current AP");
pmksa_cache_free_entry(pmksa, pos, 1);
+
+ /*
+ * If OKC is used, there may be other PMKSA cache
+ * entries based on the same PMK. These needs to be
+ * flushed so that a new entry can be created based on
+ * the new PMK.
+ */
+ pmksa_cache_flush(pmksa, network_ctx);
break;
}
prev = pos;
@@ -198,7 +207,6 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
"entry (for " MACSTR ") to make room for new one",
MAC2STR(pos->aa));
- wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid);
pmksa_cache_free_entry(pmksa, pos, 0);
}
@@ -229,6 +237,39 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
/**
+ * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @network_ctx: Network configuration context or %NULL to flush all entries
+ */
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+{
+ struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
+ int removed = 0;
+
+ entry = pmksa->pmksa;
+ while (entry) {
+ if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+ wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
+ "for " MACSTR, MAC2STR(entry->aa));
+ if (prev)
+ prev->next = entry->next;
+ else
+ pmksa->pmksa = entry->next;
+ tmp = entry;
+ entry = entry->next;
+ pmksa_cache_free_entry(pmksa, tmp, 0);
+ removed++;
+ } else {
+ prev = entry;
+ entry = entry->next;
+ }
+ }
+ if (removed)
+ pmksa_cache_set_expiration(pmksa);
+}
+
+
+/**
* pmksa_cache_deinit - Free all entries in PMKSA cache
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
*/
@@ -273,22 +314,6 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
}
-/**
- * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
- *
- * Clear references to old data structures when wpa_supplicant is reconfigured.
- */
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
- struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
- while (entry) {
- entry->network_ctx = NULL;
- entry = entry->next;
- }
-}
-
-
static struct rsn_pmksa_cache_entry *
pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
const struct rsn_pmksa_cache_entry *old_entry,
@@ -327,6 +352,7 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
{
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+ wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa));
if (network_ctx == NULL)
return NULL;
while (entry) {
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index a1447e5..840827d 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -57,7 +57,6 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
void pmksa_cache_clear_current(struct wpa_sm *sm);
int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
@@ -66,6 +65,7 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
void *network_ctx, const u8 *aa);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
@@ -106,10 +106,6 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
return NULL;
}
-static inline void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
-}
-
static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
{
}
@@ -122,6 +118,11 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
return -1;
}
+static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
+ void *network_ctx)
+{
+}
+
#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
#endif /* PMKSA_CACHE_H */
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index 6109f5e..fefca83 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -22,7 +22,6 @@
#include "preauth.h"
#include "pmksa_cache.h"
#include "wpa_i.h"
-#include "common/ieee802_11_defs.h"
#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index e751867..27090e3 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -88,6 +88,8 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
#define TDLS_MAX_IE_LEN 80
+#define IEEE80211_MAX_SUPP_RATES 32
+
struct wpa_tdls_peer {
struct wpa_tdls_peer *next;
int initiator; /* whether this end was initiator for TDLS setup */
@@ -119,6 +121,11 @@ struct wpa_tdls_peer {
int buf_len; /* length of TPK message for retransmission */
u8 *buf; /* buffer for TPK message */
} sm_tmr;
+
+ u16 capability;
+
+ u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+ size_t supp_rates_len;
};
@@ -214,7 +221,9 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
}
if (action_code == WLAN_TDLS_SETUP_CONFIRM ||
- action_code == WLAN_TDLS_TEARDOWN)
+ action_code == WLAN_TDLS_TEARDOWN ||
+ action_code == WLAN_TDLS_DISCOVERY_REQUEST ||
+ action_code == WLAN_TDLS_DISCOVERY_RESPONSE)
return 0; /* No retries */
for (peer = sm->tdls; peer; peer = peer->next) {
@@ -253,6 +262,27 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
}
+static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+ u16 reason_code, int free_peer)
+{
+ int ret;
+
+ if (sm->tdls_external_setup) {
+ ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
+
+ /* disable the link after teardown was sent */
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+ } else {
+ ret = wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+ }
+
+ if (sm->tdls_external_setup || free_peer)
+ wpa_tdls_peer_free(sm, peer);
+
+ return ret;
+}
+
+
static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
{
@@ -291,15 +321,11 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
wpa_tdls_tpk_retry_timeout, sm, peer);
} else {
- wpa_printf(MSG_INFO, "Sending Tear_Down Request");
- wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
-
- wpa_printf(MSG_INFO, "Clearing SM: Peerkey(" MACSTR ")",
- MAC2STR(peer->addr));
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
- /* clear the Peerkey statemachine */
- wpa_tdls_peer_free(sm, peer);
+ wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request");
+ wpa_tdls_do_teardown(sm, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
}
}
@@ -576,7 +602,8 @@ static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx)
} else {
wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
" - tear down", MAC2STR(peer->addr));
- wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+ wpa_tdls_do_teardown(sm, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
}
}
@@ -615,8 +642,7 @@ static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
}
-int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
- u16 reason_code)
+int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
{
struct wpa_tdls_peer *peer;
struct wpa_tdls_ftie *ftie;
@@ -625,7 +651,7 @@ int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
u8 *rbuf, *pos;
int ielen;
- if (sm->tdls_disabled)
+ if (sm->tdls_disabled || !sm->tdls_supported)
return -1;
/* Find the node and free from the list */
@@ -677,10 +703,11 @@ int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
ftie->ie_len += 170;
*pos++ = 255; /* FTIE subelem */
*pos++ = 168; /* FTIE subelem length */
+ pos += 168;
}
#endif /* CONFIG_TDLS_TESTING */
wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TDLS Teardown handshake",
- (u8 *) ftie, sizeof(*ftie));
+ (u8 *) ftie, pos - (u8 *) ftie);
/* compute MIC before sending */
wpa_tdls_linkid(sm, peer, &lnkid);
@@ -705,6 +732,50 @@ skip_ies:
}
+int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
+{
+ struct wpa_tdls_peer *peer;
+
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return -1;
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (peer == NULL) {
+ wpa_printf(MSG_DEBUG, "TDLS: Could not find peer " MACSTR
+ " for link Teardown", MAC2STR(addr));
+ return -1;
+ }
+
+ if (!peer->tpk_success) {
+ wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+ " not connected - cannot Teardown link", MAC2STR(addr));
+ return -1;
+ }
+
+ return wpa_tdls_do_teardown(sm, peer, reason_code, 0);
+}
+
+
+void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
+{
+ struct wpa_tdls_peer *peer;
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (peer) {
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
+ wpa_tdls_peer_free(sm, peer);
+ }
+}
+
+
static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -802,6 +873,26 @@ static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst,
}
+static struct wpa_tdls_peer *
+wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr)
+{
+ struct wpa_tdls_peer *peer;
+
+ wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR,
+ MAC2STR(addr));
+
+ peer = os_zalloc(sizeof(*peer));
+ if (peer == NULL)
+ return NULL;
+
+ os_memcpy(peer->addr, addr, ETH_ALEN);
+ peer->next = sm->tdls;
+ sm->tdls = peer;
+
+ return peer;
+}
+
+
static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm,
struct wpa_tdls_peer *peer)
{
@@ -972,7 +1063,7 @@ skip_ies:
"Handshake Message 1 (peer " MACSTR ")",
MAC2STR(peer->addr));
- wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 0, 0,
+ wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 1, 0,
rbuf, pos - rbuf);
os_free(rbuf);
@@ -1144,6 +1235,105 @@ skip_ies:
}
+static int wpa_tdls_send_discovery_response(struct wpa_sm *sm,
+ struct wpa_tdls_peer *peer,
+ u8 dialog_token)
+{
+ wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response "
+ "(peer " MACSTR ")", MAC2STR(peer->addr));
+
+ return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
+ dialog_token, 0, NULL, 0);
+}
+
+
+static int
+wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
+ const u8 *buf, size_t len)
+{
+ struct wpa_eapol_ie_parse kde;
+ const struct wpa_tdls_lnkid *lnkid;
+ struct wpa_tdls_peer *peer;
+ size_t min_req_len = sizeof(struct wpa_tdls_frame) +
+ 1 /* dialog token */ + sizeof(struct wpa_tdls_lnkid);
+ u8 dialog_token;
+
+ wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from " MACSTR,
+ MAC2STR(addr));
+
+ if (len < min_req_len) {
+ wpa_printf(MSG_DEBUG, "TDLS Discovery Request is too short: "
+ "%d", (int) len);
+ return -1;
+ }
+
+ dialog_token = buf[sizeof(struct wpa_tdls_frame)];
+
+ if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1,
+ len - (sizeof(struct wpa_tdls_frame) + 1),
+ &kde) < 0)
+ return -1;
+
+ if (!kde.lnkid) {
+ wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery "
+ "Request");
+ return -1;
+ }
+
+ lnkid = (const struct wpa_tdls_lnkid *) kde.lnkid;
+
+ if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from different "
+ " BSS " MACSTR, MAC2STR(lnkid->bssid));
+ return -1;
+ }
+
+ peer = wpa_tdls_add_peer(sm, addr);
+ if (peer == NULL)
+ return -1;
+
+ return wpa_tdls_send_discovery_response(sm, peer, dialog_token);
+}
+
+
+int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr)
+{
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer "
+ MACSTR, MAC2STR(addr));
+ return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST,
+ 1, 0, NULL, 0);
+}
+
+
+static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->supp_rates) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported rates received");
+ return -1;
+ }
+
+ peer->supp_rates_len = kde->supp_rates_len - 2;
+ if (peer->supp_rates_len > IEEE80211_MAX_SUPP_RATES)
+ peer->supp_rates_len = IEEE80211_MAX_SUPP_RATES;
+ os_memcpy(peer->supp_rates, kde->supp_rates + 2, peer->supp_rates_len);
+
+ if (kde->ext_supp_rates) {
+ int clen = kde->ext_supp_rates_len - 2;
+ if (peer->supp_rates_len + clen > IEEE80211_MAX_SUPP_RATES)
+ clen = IEEE80211_MAX_SUPP_RATES - peer->supp_rates_len;
+ os_memcpy(peer->supp_rates + peer->supp_rates_len,
+ kde->ext_supp_rates + 2, clen);
+ peer->supp_rates_len += clen;
+ }
+
+ return 0;
+}
+
+
static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -1166,6 +1356,7 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
u16 ielen;
u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
int tdls_prohibited = sm->tdls_prohibited;
+ int existing_peer = 0;
if (len < 3 + 3)
return -1;
@@ -1178,7 +1369,22 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken);
- cpos += 2; /* capability information */
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) {
+ existing_peer = 1;
+ break;
+ }
+ }
+
+ if (peer == NULL) {
+ peer = wpa_tdls_add_peer(sm, src_addr);
+ if (peer == NULL)
+ goto error;
+ }
+
+ /* capability information */
+ peer->capability = WPA_GET_LE16(cpos);
+ cpos += 2;
ielen = len - (cpos - buf); /* start of IE in buf */
if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) {
@@ -1203,6 +1409,9 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR,
MAC2STR(src_addr));
+ if (copy_supp_rates(&kde, peer) < 0)
+ goto error;
+
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
for (peer = sm->tdls; peer; peer = peer->next) {
@@ -1210,12 +1419,9 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
break;
}
if (peer == NULL) {
- peer = os_zalloc(sizeof(*peer));
+ peer = wpa_tdls_add_peer(sm, src_addr);
if (peer == NULL)
goto error;
- os_memcpy(peer->addr, src_addr, ETH_ALEN);
- peer->next = sm->tdls;
- sm->tdls = peer;
}
wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of "
"TDLS setup - send own request");
@@ -1302,26 +1508,10 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
}
skip_rsn:
- /* Find existing entry and if found, use that instead of adding
- * a new one; how to handle the case where both ends initiate at the
+ /* If found, use existing entry instead of adding a new one;
+ * how to handle the case where both ends initiate at the
* same time? */
- for (peer = sm->tdls; peer; peer = peer->next) {
- if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
- break;
- }
-
- if (peer == NULL) {
- wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
- "peer, creating one for " MACSTR,
- MAC2STR(src_addr));
- peer = os_malloc(sizeof(*peer));
- if (peer == NULL)
- goto error;
- os_memset(peer, 0, sizeof(*peer));
- os_memcpy(peer->addr, src_addr, ETH_ALEN);
- peer->next = sm->tdls;
- sm->tdls = peer;
- } else {
+ if (existing_peer) {
if (peer->tpk_success) {
wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
"direct link is enabled - tear down the "
@@ -1332,7 +1522,11 @@ skip_rsn:
* some drivers handling the new request frame. */
wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
#else
- wpa_tdls_del_key(sm, peer);
+ if (sm->tdls_external_setup)
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+ src_addr);
+ else
+ wpa_tdls_del_key(sm, peer);
#endif
wpa_tdls_peer_free(sm, peer);
}
@@ -1360,6 +1554,19 @@ skip_rsn:
}
}
+#ifdef CONFIG_TDLS_TESTING
+ if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
+ if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) {
+ /*
+ * The request frame from us is going to win, so do not
+ * replace information based on this request frame from
+ * the peer.
+ */
+ goto skip_rsn_check;
+ }
+ }
+#endif /* CONFIG_TDLS_TESTING */
+
peer->initiator = 0; /* Need to check */
peer->dtoken = dtoken;
@@ -1433,8 +1640,14 @@ skip_rsn:
wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
skip_rsn_check:
+ /* add the peer to the driver as a "setup in progress" peer */
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
- wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer);
+ if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
+ wpa_tdls_disable_link(sm, peer->addr);
+ goto error;
+ }
return 0;
@@ -1467,6 +1680,11 @@ static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
}
#endif /* CONFIG_TDLS_TESTING */
}
+
+ /* add supported rates and capabilities to the TDLS peer */
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
+ peer->supp_rates, peer->supp_rates_len);
+
wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
}
@@ -1510,6 +1728,8 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
if (status != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u",
status);
+ if (sm->tdls_external_setup)
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
return -1;
}
@@ -1522,7 +1742,10 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
if (len < 3 + 2 + 1 + 2)
return -1;
- pos += 2; /* capability information */
+
+ /* capability information */
+ peer->capability = WPA_GET_LE16(pos);
+ pos += 2;
ielen = len - (pos - buf); /* start of IE in buf */
if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) {
@@ -1553,6 +1776,9 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
goto error;
}
+ if (copy_supp_rates(&kde, peer) < 0)
+ goto error;
+
if (!wpa_tdls_get_privacy(sm)) {
peer->rsnie_p_len = 0;
peer->cipher = WPA_CIPHER_NONE;
@@ -1644,6 +1870,8 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
/* Discard the frame */
wpa_tdls_del_key(sm, peer);
wpa_tdls_peer_free(sm, peer);
+ if (sm->tdls_external_setup)
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
return -1;
}
@@ -1663,6 +1891,8 @@ skip_rsn:
error:
wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
status);
+ if (sm->tdls_external_setup)
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
return -1;
}
@@ -1703,6 +1933,8 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (status != 0) {
wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u",
status);
+ if (sm->tdls_external_setup)
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
return -1;
}
pos += 2 /* status code */ + 1 /* dialog token */;
@@ -1775,6 +2007,8 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (lifetime != peer->lifetime) {
wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in "
"TPK M3 (expected %u)", lifetime, peer->lifetime);
+ if (sm->tdls_external_setup)
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
return -1;
}
@@ -1823,7 +2057,7 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
struct wpa_tdls_peer *peer;
int tdls_prohibited = sm->tdls_prohibited;
- if (sm->tdls_disabled)
+ if (sm->tdls_disabled || !sm->tdls_supported)
return -1;
#ifdef CONFIG_TDLS_TESTING
@@ -1849,20 +2083,22 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
}
if (peer == NULL) {
- wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
- "peer, creating one for " MACSTR, MAC2STR(addr));
- peer = os_malloc(sizeof(*peer));
+ peer = wpa_tdls_add_peer(sm, addr);
if (peer == NULL)
return -1;
- os_memset(peer, 0, sizeof(*peer));
- os_memcpy(peer->addr, addr, ETH_ALEN);
- peer->next = sm->tdls;
- sm->tdls = peer;
}
peer->initiator = 1;
- return wpa_tdls_send_tpk_m1(sm, peer);
+ /* add the peer to the driver as a "setup in progress" peer */
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
+ if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
+ wpa_tdls_disable_link(sm, peer->addr);
+ return -1;
+ }
+
+ return 0;
}
@@ -1870,7 +2106,7 @@ int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
{
struct wpa_tdls_peer *peer;
- if (sm->tdls_disabled)
+ if (sm->tdls_disabled || !sm->tdls_supported)
return -1;
for (peer = sm->tdls; peer; peer = peer->next) {
@@ -1881,6 +2117,14 @@ int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
if (peer == NULL || !peer->tpk_success)
return -1;
+ if (sm->tdls_external_setup) {
+ /*
+ * Disable previous link to allow renegotiation to be completed
+ * on AP path.
+ */
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+ }
+
return wpa_tdls_start(sm, addr);
}
@@ -1899,8 +2143,9 @@ static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr,
wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation",
buf, len);
- if (sm->tdls_disabled) {
- wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled");
+ if (sm->tdls_disabled || !sm->tdls_supported) {
+ wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled "
+ "or unsupported by driver");
return;
}
@@ -1937,6 +2182,9 @@ static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr,
case WLAN_TDLS_TEARDOWN:
wpa_tdls_recv_teardown(sm, src_addr, buf, len);
break;
+ case WLAN_TDLS_DISCOVERY_REQUEST:
+ wpa_tdls_process_discovery_request(sm, src_addr, buf, len);
+ break;
default:
/* Kernel code will process remaining frames */
wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u",
@@ -1969,6 +2217,21 @@ int wpa_tdls_init(struct wpa_sm *sm)
return -1;
}
+ /*
+ * Drivers that support TDLS but don't implement the get_capa callback
+ * are assumed to perform everything internally
+ */
+ if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported,
+ &sm->tdls_external_setup) < 0) {
+ sm->tdls_supported = 1;
+ sm->tdls_external_setup = 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "TDLS: TDLS operation%s supported by "
+ "driver", sm->tdls_supported ? "" : " not");
+ wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup",
+ sm->tdls_external_setup ? "external" : "internal");
+
return 0;
}
@@ -2067,3 +2330,9 @@ void wpa_tdls_enable(struct wpa_sm *sm, int enabled)
wpa_printf(MSG_DEBUG, "TDLS: %s", enabled ? "enabled" : "disabled");
sm->tdls_disabled = !enabled;
}
+
+
+int wpa_tdls_is_external_setup(struct wpa_sm *sm)
+{
+ return sm->tdls_external_setup;
+}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 7c0ac87..f35f9ee 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -396,7 +396,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
const u8 *_buf = (const u8 *) (key + 1);
size_t len = WPA_GET_BE16(key->key_data_length);
wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
- wpa_supplicant_parse_ies(_buf, len, &ie);
+ if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0)
+ goto failed;
if (ie.pmkid) {
wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
"Authenticator", ie.pmkid, PMKID_LEN);
@@ -476,7 +477,7 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
* Start preauthentication after a short wait to avoid a
* possible race condition between the data receive and key
* configuration after the 4-Way Handshake. This increases the
- * likelyhood of the first preauth EAPOL-Start frame getting to
+ * likelihood of the first preauth EAPOL-Start frame getting to
* the target AP.
*/
eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
@@ -1085,7 +1086,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
pos = (const u8 *) (key + 1);
len = WPA_GET_BE16(key->key_data_length);
wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
- wpa_supplicant_parse_ies(pos, len, &ie);
+ if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
+ goto failed;
if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: GTK IE in unencrypted key data");
@@ -1174,6 +1176,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
+ wpa_sm_set_rekey_offload(sm);
+
return;
failed:
@@ -1191,7 +1195,8 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
struct wpa_eapol_ie_parse ie;
wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
- wpa_supplicant_parse_ies(keydata, keydatalen, &ie);
+ if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0)
+ return -1;
if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: GTK IE in unencrypted key data");
@@ -1392,6 +1397,8 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
wpa_sm_cancel_auth_timeout(sm);
wpa_sm_set_state(sm, WPA_COMPLETED);
+
+ wpa_sm_set_rekey_offload(sm);
} else {
wpa_supplicant_key_neg_complete(sm, sm->bssid,
key_info &
@@ -2265,8 +2272,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->ssid_len = 0;
sm->wpa_ptk_rekey = 0;
}
- if (config == NULL || config->network_ctx != sm->network_ctx)
- pmksa_cache_notify_reconfig(sm->pmksa);
}
@@ -2644,3 +2649,17 @@ int wpa_sm_has_ptk(struct wpa_sm *sm)
return 0;
return sm->ptk_set;
}
+
+
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
+{
+ os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
+}
+
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
+{
+#ifndef CONFIG_NO_WPA2
+ pmksa_cache_flush(sm->pmksa, network_ctx);
+#endif /* CONFIG_NO_WPA2 */
+}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 111597c..4c1750f 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -56,11 +56,18 @@ struct wpa_sm_ctx {
const u8 *ies, size_t ies_len);
int (*mark_authenticated)(void *ctx, const u8 *target_ap);
#ifdef CONFIG_TDLS
+ int (*tdls_get_capa)(void *ctx, int *tdls_supported,
+ int *tdls_ext_setup);
int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token,
u16 status_code, const u8 *buf, size_t len);
int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
+ int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
+ u16 capability, const u8 *supp_rates,
+ size_t supp_rates_len);
#endif /* CONFIG_TDLS */
+ void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+ const u8 *replay_ctr);
};
@@ -132,6 +139,10 @@ int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
void wpa_sm_drop_sa(struct wpa_sm *sm);
int wpa_sm_has_ptk(struct wpa_sm *sm);
+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);
+
#else /* CONFIG_NO_WPA */
static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -277,6 +288,16 @@ static inline int wpa_sm_has_ptk(struct wpa_sm *sm)
return 0;
}
+static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm,
+ const u8 *replay_ctr)
+{
+}
+
+static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm,
+ void *network_ctx)
+{
+}
+
#endif /* CONFIG_NO_WPA */
#ifdef CONFIG_PEERKEY
@@ -342,10 +363,13 @@ void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr);
-int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
- u16 reason_code);
+int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_init(struct wpa_sm *sm);
void wpa_tdls_deinit(struct wpa_sm *sm);
void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
+void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_is_external_setup(struct wpa_sm *sm);
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index da6e966..dbf5996 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -21,35 +21,9 @@
#include "common/ieee802_11_common.h"
#include "wpa.h"
#include "wpa_i.h"
-#include "wpa_ie.h"
#ifdef CONFIG_IEEE80211R
-struct wpa_ft_ies {
- const u8 *mdie;
- size_t mdie_len;
- const u8 *ftie;
- size_t ftie_len;
- const u8 *r1kh_id;
- const u8 *gtk;
- size_t gtk_len;
- const u8 *r0kh_id;
- size_t r0kh_id_len;
- const u8 *rsn;
- size_t rsn_len;
- const u8 *rsn_pmkid;
- const u8 *tie;
- size_t tie_len;
- const u8 *igtk;
- size_t igtk_len;
- const u8 *ric;
- size_t ric_len;
-};
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
- struct wpa_ft_ies *parse);
-
-
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key,
struct wpa_ptk *ptk, size_t ptk_len)
@@ -347,155 +321,6 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
}
-static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
- struct wpa_ft_ies *parse)
-{
- const u8 *end, *pos;
-
- parse->ftie = ie;
- parse->ftie_len = ie_len;
-
- pos = ie + sizeof(struct rsn_ftie);
- end = ie + ie_len;
-
- while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
- switch (pos[0]) {
- case FTIE_SUBELEM_R1KH_ID:
- if (pos[1] != FT_R1KH_ID_LEN) {
- wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
- "length in FTIE: %d", pos[1]);
- return -1;
- }
- parse->r1kh_id = pos + 2;
- break;
- case FTIE_SUBELEM_GTK:
- parse->gtk = pos + 2;
- parse->gtk_len = pos[1];
- break;
- case FTIE_SUBELEM_R0KH_ID:
- if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
- wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
- "length in FTIE: %d", pos[1]);
- return -1;
- }
- parse->r0kh_id = pos + 2;
- parse->r0kh_id_len = pos[1];
- break;
-#ifdef CONFIG_IEEE80211W
- case FTIE_SUBELEM_IGTK:
- parse->igtk = pos + 2;
- parse->igtk_len = pos[1];
- break;
-#endif /* CONFIG_IEEE80211W */
- }
-
- pos += 2 + pos[1];
- }
-
- return 0;
-}
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
- struct wpa_ft_ies *parse)
-{
- const u8 *end, *pos;
- struct wpa_ie_data data;
- int ret;
- const struct rsn_ftie *ftie;
- int prot_ie_count = 0;
-
- os_memset(parse, 0, sizeof(*parse));
- if (ies == NULL)
- return 0;
-
- pos = ies;
- end = ies + ies_len;
- while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
- switch (pos[0]) {
- case WLAN_EID_RSN:
- parse->rsn = pos + 2;
- parse->rsn_len = pos[1];
- ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
- parse->rsn_len + 2,
- &data);
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "FT: Failed to parse "
- "RSN IE: %d", ret);
- return -1;
- }
- if (data.num_pmkid == 1 && data.pmkid)
- parse->rsn_pmkid = data.pmkid;
- break;
- case WLAN_EID_MOBILITY_DOMAIN:
- parse->mdie = pos + 2;
- parse->mdie_len = pos[1];
- break;
- case WLAN_EID_FAST_BSS_TRANSITION:
- if (pos[1] < sizeof(*ftie))
- return -1;
- ftie = (const struct rsn_ftie *) (pos + 2);
- prot_ie_count = ftie->mic_control[1];
- if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
- return -1;
- break;
- case WLAN_EID_TIMEOUT_INTERVAL:
- parse->tie = pos + 2;
- parse->tie_len = pos[1];
- break;
- case WLAN_EID_RIC_DATA:
- if (parse->ric == NULL)
- parse->ric = pos;
- }
-
- pos += 2 + pos[1];
- }
-
- if (prot_ie_count == 0)
- return 0; /* no MIC */
-
- /*
- * Check that the protected IE count matches with IEs included in the
- * frame.
- */
- if (parse->rsn)
- prot_ie_count--;
- if (parse->mdie)
- prot_ie_count--;
- if (parse->ftie)
- prot_ie_count--;
- if (parse->tie)
- prot_ie_count--;
- if (prot_ie_count < 0) {
- wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
- "the protected IE count");
- return -1;
- }
-
- if (prot_ie_count == 0 && parse->ric) {
- wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
- "included in protected IE count");
- return -1;
- }
-
- /* Determine the end of the RIC IE(s) */
- pos = parse->ric;
- while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
- prot_ie_count) {
- prot_ie_count--;
- pos += 2 + pos[1];
- }
- parse->ric_len = pos - parse->ric;
- if (prot_ie_count) {
- wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
- "frame", (int) prot_ie_count);
- return -1;
- }
-
- return 0;
-}
-
-
static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
{
int keylen;
@@ -950,8 +775,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
}
count = 3;
- if (parse.tie)
- count++;
+ if (parse.ric)
+ count += ieee802_11_ie_count(parse.ric, parse.ric_len);
if (ftie->mic_control[1] != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 09a2e4f..39124c4 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -98,6 +98,15 @@ struct wpa_sm {
struct wpa_tdls_peer *tdls;
int tdls_prohibited;
int tdls_disabled;
+
+ /* The driver supports TDLS */
+ int tdls_supported;
+
+ /*
+ * The driver requires explicit discovery/setup/teardown frames sent
+ * to it via tdls_mgmt.
+ */
+ int tdls_external_setup;
#endif /* CONFIG_TDLS */
#ifdef CONFIG_IEEE80211R
@@ -244,7 +253,25 @@ static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm,
return -1;
}
+static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm)
+{
+ if (!sm->ctx->set_rekey_offload)
+ return;
+ sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
+ sm->ptk.kck, sm->rx_replay_counter);
+}
+
#ifdef CONFIG_TDLS
+static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
+ int *tdls_supported,
+ int *tdls_ext_setup)
+{
+ if (sm->ctx->tdls_get_capa)
+ return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported,
+ tdls_ext_setup);
+ return -1;
+}
+
static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token,
u16 status_code, const u8 *buf,
@@ -264,6 +291,18 @@ static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper,
return sm->ctx->tdls_oper(sm->ctx->ctx, oper, peer);
return -1;
}
+
+static inline int
+wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
+ u16 capability, const u8 *supp_rates,
+ size_t supp_rates_len)
+{
+ if (sm->ctx->tdls_peer_addset)
+ return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
+ capability, supp_rates,
+ supp_rates_len);
+ return -1;
+}
#endif /* CONFIG_TDLS */
void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 654cc1f..cbbc54f 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -424,11 +424,19 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
pos, 2 + pos[1]);
}
} else if (*pos == WLAN_EID_LINK_ID) {
- ie->lnkid = pos;
- ie->lnkid_len = pos[1] + 2;
+ if (pos[1] >= 18) {
+ ie->lnkid = pos;
+ ie->lnkid_len = pos[1] + 2;
+ }
} else if (*pos == WLAN_EID_EXT_CAPAB) {
ie->ext_capab = pos;
ie->ext_capab_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_SUPP_RATES) {
+ ie->supp_rates = pos;
+ ie->supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+ ie->ext_supp_rates = pos;
+ ie->ext_supp_rates_len = pos[1] + 2;
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
ret = wpa_parse_generic(pos, end, ie);
if (ret < 0)
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index f939b13..c13d94c 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -51,6 +51,10 @@ struct wpa_eapol_ie_parse {
size_t lnkid_len;
const u8 *ext_capab;
size_t ext_capab_len;
+ const u8 *supp_rates;
+ size_t supp_rates_len;
+ const u8 *ext_supp_rates;
+ size_t ext_supp_rates_len;
};
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/tls/Makefile b/src/tls/Makefile
index a2da096..27cdfca 100644
--- a/src/tls/Makefile
+++ b/src/tls/Makefile
@@ -11,6 +11,8 @@ include ../lib.rules
CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+CFLAGS += -DCONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV12
LIB_OBJS= \
asn1.o \
diff --git a/src/tls/libtommath.c b/src/tls/libtommath.c
index 1374264..7c9857f 100644
--- a/src/tls/libtommath.c
+++ b/src/tls/libtommath.c
@@ -572,7 +572,7 @@ static int mp_mod (mp_int * a, mp_int * b, mp_int * c)
/* this is a shell function that calls either the normal or Montgomery
* exptmod functions. Originally the call to the montgomery code was
- * embedded in the normal function but that wasted alot of stack space
+ * embedded in the normal function but that wasted a lot of stack space
* for nothing (since 99% of the time the Montgomery code would be called)
*/
static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
@@ -2207,7 +2207,7 @@ static int mp_2expt (mp_int * a, int b)
/* zero a as per default */
mp_zero (a);
- /* grow a to accomodate the single bit */
+ /* grow a to accommodate the single bit */
if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
return res;
}
@@ -2319,7 +2319,7 @@ CLEANUP:
}
-/* multiplies |a| * |b| and only computes upto digs digits of result
+/* multiplies |a| * |b| and only computes up to digs digits of result
* HAC pp. 595, Algorithm 14.12 Modified so you can control how
* many digits of output are created.
*/
@@ -2678,7 +2678,7 @@ mp_montgomery_setup (mp_int * n, mp_digit * rho)
*
* Based on Algorithm 14.32 on pp.601 of HAC.
*/
-int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+static int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
{
int ix, res, olduse;
mp_word W[MP_WARRAY];
@@ -2829,7 +2829,7 @@ static int mp_mul_2(mp_int * a, mp_int * b)
{
int x, res, oldused;
- /* grow to accomodate result */
+ /* grow to accommodate result */
if (b->alloc < a->used + 1) {
if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
return res;
@@ -2891,8 +2891,8 @@ static int mp_mul_2(mp_int * a, mp_int * b)
/*
* shifts with subtractions when the result is greater than b.
*
- * The method is slightly modified to shift B unconditionally upto just under
- * the leading bit of b. This saves alot of multiple precision shifting.
+ * The method is slightly modified to shift B unconditionally up to just under
+ * the leading bit of b. This saves a lot of multiple precision shifting.
*/
static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
{
diff --git a/src/tls/pkcs5.c b/src/tls/pkcs5.c
index 4291b84..fd9e346 100644
--- a/src/tls/pkcs5.c
+++ b/src/tls/pkcs5.c
@@ -32,7 +32,7 @@ struct pkcs5_params {
};
-enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
+static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
{
if (oid->len == 7 &&
oid->oid[0] == 1 /* iso */ &&
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 8b7e26f..d0da588 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -1,5 +1,5 @@
/*
- * TLSv1 client (RFC 2246)
+ * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -67,7 +67,8 @@ int tls_derive_keys(struct tlsv1_client *conn,
os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
TLS_RANDOM_LEN);
- if (tls_prf(pre_master_secret, pre_master_secret_len,
+ if (tls_prf(conn->rl.tls_version,
+ pre_master_secret, pre_master_secret_len,
"master secret", seed, 2 * TLS_RANDOM_LEN,
conn->master_secret, TLS_MASTER_SECRET_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
@@ -80,9 +81,11 @@ int tls_derive_keys(struct tlsv1_client *conn,
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
- key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
- conn->rl.iv_size);
- if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len);
+ if (conn->rl.tls_version == TLS_VERSION_1)
+ key_block_len += 2 * conn->rl.iv_size;
+ if (tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
"key expansion", seed, 2 * TLS_RANDOM_LEN,
key_block, key_block_len)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
@@ -107,12 +110,21 @@ int tls_derive_keys(struct tlsv1_client *conn,
os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
pos += conn->rl.key_material_len;
- /* client_write_IV */
- os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
- pos += conn->rl.iv_size;
- /* server_write_IV */
- os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
- pos += conn->rl.iv_size;
+ if (conn->rl.tls_version == TLS_VERSION_1) {
+ /* client_write_IV */
+ os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
+ pos += conn->rl.iv_size;
+ /* server_write_IV */
+ os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
+ pos += conn->rl.iv_size;
+ } else {
+ /*
+ * Use IV field to set the mask value for TLS v1.1. A fixed
+ * mask of zero is used per the RFC 4346, 6.2.3.2 CBC Block
+ * Cipher option 2a.
+ */
+ os_memset(conn->rl.write_iv, 0, conn->rl.iv_size);
+ }
return 0;
}
@@ -126,17 +138,23 @@ int tls_derive_keys(struct tlsv1_client *conn,
* @out_len: Length of the output buffer.
* @appl_data: Pointer to application data pointer, or %NULL if dropped
* @appl_data_len: Pointer to variable that is set to appl_data length
+ * @need_more_data: Set to 1 if more data would be needed to complete
+ * processing
* Returns: Pointer to output data, %NULL on failure
*/
u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
const u8 *in_data, size_t in_len,
size_t *out_len, u8 **appl_data,
- size_t *appl_data_len)
+ size_t *appl_data_len, int *need_more_data)
{
const u8 *pos, *end;
- u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
+ u8 *msg = NULL, *in_msg = NULL, *in_pos, *in_end, alert, ct;
size_t in_msg_len;
int no_appl_data;
+ int used;
+
+ if (need_more_data)
+ *need_more_data = 0;
if (conn->state == CLIENT_HELLO) {
if (in_len)
@@ -144,6 +162,19 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
return tls_send_client_hello(conn, out_len);
}
+ if (conn->partial_input) {
+ if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+ "memory for pending record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ goto failed;
+ }
+ wpabuf_put_data(conn->partial_input, in_data, in_len);
+ in_data = wpabuf_head(conn->partial_input);
+ in_len = wpabuf_len(conn->partial_input);
+ }
+
if (in_data == NULL || in_len == 0)
return NULL;
@@ -156,13 +187,33 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
/* Each received packet may include multiple records */
while (pos < end) {
in_msg_len = in_len;
- if (tlsv1_record_receive(&conn->rl, pos, end - pos,
- in_msg, &in_msg_len, &alert)) {
+ used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+ in_msg, &in_msg_len, &alert);
+ if (used < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
"record failed");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
goto failed;
}
+ if (used == 0) {
+ struct wpabuf *partial;
+ wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
+ partial = wpabuf_alloc_copy(pos, end - pos);
+ wpabuf_free(conn->partial_input);
+ conn->partial_input = partial;
+ if (conn->partial_input == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+ "allocate memory for pending "
+ "record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ goto failed;
+ }
+ os_free(in_msg);
+ if (need_more_data)
+ *need_more_data = 1;
+ return NULL;
+ }
ct = pos[0];
in_pos = in_msg;
@@ -180,7 +231,7 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
in_pos += in_msg_len;
}
- pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ pos += used;
}
os_free(in_msg);
@@ -192,6 +243,8 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
failed:
os_free(in_msg);
if (conn->alert_level) {
+ wpabuf_free(conn->partial_input);
+ conn->partial_input = NULL;
conn->state = FAILED;
os_free(msg);
msg = tlsv1_client_send_alert(conn, conn->alert_level,
@@ -202,6 +255,11 @@ failed:
*out_len = 0;
}
+ if (need_more_data == NULL || !(*need_more_data)) {
+ wpabuf_free(conn->partial_input);
+ conn->partial_input = NULL;
+ }
+
return msg;
}
@@ -227,10 +285,8 @@ int tlsv1_client_encrypt(struct tlsv1_client *conn,
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
in_data, in_len);
- os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
-
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
- out_data, out_len, in_len, &rlen) < 0) {
+ out_data, out_len, in_data, in_len, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -246,58 +302,116 @@ int tlsv1_client_encrypt(struct tlsv1_client *conn,
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @in_data: Pointer to input buffer (encrypted TLS data)
* @in_len: Input buffer length
- * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
- * @out_len: Maximum out_data length
- * Returns: Number of bytes written to out_data, -1 on failure
+ * @need_more_data: Set to 1 if more data would be needed to complete
+ * processing
+ * Returns: Decrypted data or %NULL on failure
*
* This function is used after TLS handshake has been completed successfully to
* receive data from the encrypted tunnel.
*/
-int tlsv1_client_decrypt(struct tlsv1_client *conn,
- const u8 *in_data, size_t in_len,
- u8 *out_data, size_t out_len)
+struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
+ const u8 *in_data, size_t in_len,
+ int *need_more_data)
{
const u8 *in_end, *pos;
- int res;
- u8 alert, *out_end, *out_pos;
+ int used;
+ u8 alert, *out_pos, ct;
size_t olen;
+ struct wpabuf *buf = NULL;
+
+ if (need_more_data)
+ *need_more_data = 0;
+
+ if (conn->partial_input) {
+ if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+ "memory for pending record");
+ alert = TLS_ALERT_INTERNAL_ERROR;
+ goto fail;
+ }
+ wpabuf_put_data(conn->partial_input, in_data, in_len);
+ in_data = wpabuf_head(conn->partial_input);
+ in_len = wpabuf_len(conn->partial_input);
+ }
pos = in_data;
in_end = in_data + in_len;
- out_pos = out_data;
- out_end = out_data + out_len;
while (pos < in_end) {
- if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
- "0x%x", pos[0]);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
+ ct = pos[0];
+ if (wpabuf_resize(&buf, in_end - pos) < 0) {
+ alert = TLS_ALERT_INTERNAL_ERROR;
+ goto fail;
}
-
- olen = out_end - out_pos;
- res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
- out_pos, &olen, &alert);
- if (res < 0) {
+ out_pos = wpabuf_put(buf, 0);
+ olen = wpabuf_tailroom(buf);
+ used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+ out_pos, &olen, &alert);
+ if (used < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
"failed");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
- return -1;
+ goto fail;
}
- out_pos += olen;
- if (out_pos > out_end) {
- wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
- "for processing the received record");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
+ if (used == 0) {
+ struct wpabuf *partial;
+ wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
+ partial = wpabuf_alloc_copy(pos, in_end - pos);
+ wpabuf_free(conn->partial_input);
+ conn->partial_input = partial;
+ if (conn->partial_input == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+ "allocate memory for pending "
+ "record");
+ alert = TLS_ALERT_INTERNAL_ERROR;
+ goto fail;
+ }
+ if (need_more_data)
+ *need_more_data = 1;
+ return buf;
}
- pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ if (ct == TLS_CONTENT_TYPE_ALERT) {
+ if (olen < 2) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+ "underflow");
+ alert = TLS_ALERT_DECODE_ERROR;
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+ out_pos[0], out_pos[1]);
+ if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+ /* Continue processing */
+ pos += used;
+ continue;
+ }
+
+ alert = out_pos[1];
+ goto fail;
+ }
+
+ if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
+ "0x%x when decrypting application data",
+ pos[0]);
+ alert = TLS_ALERT_UNEXPECTED_MESSAGE;
+ goto fail;
+ }
+
+ wpabuf_put(buf, olen);
+
+ pos += used;
}
- return out_pos - out_data;
+ wpabuf_free(conn->partial_input);
+ conn->partial_input = NULL;
+ return buf;
+
+fail:
+ wpabuf_free(buf);
+ wpabuf_free(conn->partial_input);
+ conn->partial_input = NULL;
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ return NULL;
}
@@ -352,14 +466,18 @@ struct tlsv1_client * tlsv1_client_init(void)
count = 0;
suites = conn->cipher_suites;
#ifndef CONFIG_CRYPTO_INTERNAL
+ suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
#endif /* CONFIG_CRYPTO_INTERNAL */
+ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
conn->num_cipher_suites = count;
+ conn->rl.tls_version = TLS_VERSION;
+
return conn;
}
@@ -378,6 +496,7 @@ void tlsv1_client_deinit(struct tlsv1_client *conn)
os_free(conn->client_hello_ext);
tlsv1_client_free_dh(conn);
tlsv1_cred_free(conn->cred);
+ wpabuf_free(conn->partial_input);
os_free(conn);
}
@@ -421,7 +540,8 @@ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
TLS_RANDOM_LEN);
}
- return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ return tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
}
@@ -453,15 +573,24 @@ int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
cipher = "DES-CBC3-SHA";
break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ cipher = "ADH-AES-128-SHA256";
+ break;
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
cipher = "ADH-AES-128-SHA";
break;
case TLS_RSA_WITH_AES_256_CBC_SHA:
cipher = "AES-256-SHA";
break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "AES-256-SHA256";
+ break;
case TLS_RSA_WITH_AES_128_CBC_SHA:
cipher = "AES-128-SHA";
break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA256:
+ cipher = "AES-128-SHA256";
+ break;
default:
return -1;
}
@@ -613,8 +742,10 @@ int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
count = 0;
suites = conn->cipher_suites;
#ifndef CONFIG_CRYPTO_INTERNAL
+ suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA256;
suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
#endif /* CONFIG_CRYPTO_INTERNAL */
+ suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA256;
suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
diff --git a/src/tls/tlsv1_client.h b/src/tls/tlsv1_client.h
index a620d62..ef5e694 100644
--- a/src/tls/tlsv1_client.h
+++ b/src/tls/tlsv1_client.h
@@ -1,5 +1,5 @@
/*
- * TLSv1 client (RFC 2246)
+ * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -29,13 +29,13 @@ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
const u8 *in_data, size_t in_len,
size_t *out_len, u8 **appl_data,
- size_t *appl_data_len);
+ size_t *appl_data_len, int *need_more_data);
int tlsv1_client_encrypt(struct tlsv1_client *conn,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len);
-int tlsv1_client_decrypt(struct tlsv1_client *conn,
- const u8 *in_data, size_t in_len,
- u8 *out_data, size_t out_len);
+struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
+ const u8 *in_data, size_t in_len,
+ int *need_more_data);
int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
size_t buflen);
int tlsv1_client_shutdown(struct tlsv1_client *conn);
diff --git a/src/tls/tlsv1_client_i.h b/src/tls/tlsv1_client_i.h
index f091bcf..92912ca 100644
--- a/src/tls/tlsv1_client_i.h
+++ b/src/tls/tlsv1_client_i.h
@@ -68,6 +68,8 @@ struct tlsv1_client {
tlsv1_client_session_ticket_cb session_ticket_cb;
void *session_ticket_cb_ctx;
+
+ struct wpabuf *partial_input;
};
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index faa891a..eb0cbef 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -1,6 +1,6 @@
/*
* TLSv1 client - read handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
+#include "crypto/sha256.h"
#include "crypto/tls.h"
#include "x509v3.h"
#include "tlsv1_common.h"
@@ -38,6 +39,7 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
const u8 *pos, *end;
size_t left, len, i;
u16 cipher_suite;
+ u16 tls_version;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
@@ -79,15 +81,20 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
/* ProtocolVersion server_version */
if (end - pos < 2)
goto decode_error;
- if (WPA_GET_BE16(pos) != TLS_VERSION) {
+ tls_version = WPA_GET_BE16(pos);
+ if (!tls_version_ok(tls_version)) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
- "ServerHello");
+ "ServerHello %u.%u", pos[0], pos[1]);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_PROTOCOL_VERSION);
return -1;
}
pos += 2;
+ wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
+ tls_version_str(tls_version));
+ conn->rl.tls_version = tls_version;
+
/* Random random */
if (end - pos < TLS_RANDOM_LEN)
goto decode_error;
@@ -816,6 +823,21 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
pos, TLS_VERIFY_DATA_LEN);
+#ifdef CONFIG_TLSV12
+ if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+ hlen = SHA256_MAC_LEN;
+ if (conn->verify.sha256_server == NULL ||
+ crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+ < 0) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.sha256_server = NULL;
+ return -1;
+ }
+ conn->verify.sha256_server = NULL;
+ } else {
+#endif /* CONFIG_TLSV12 */
+
hlen = MD5_MAC_LEN;
if (conn->verify.md5_server == NULL ||
crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
@@ -837,9 +859,15 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
return -1;
}
conn->verify.sha1_server = NULL;
+ hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+ }
+#endif /* CONFIG_TLSV12 */
- if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
- "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+ if (tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "server finished", hash, hlen,
verify_data, TLS_VERIFY_DATA_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index 0898df9..35a238b 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -1,6 +1,6 @@
/*
* TLSv1 client - write handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
+#include "crypto/sha256.h"
#include "crypto/tls.h"
#include "crypto/random.h"
#include "x509v3.h"
@@ -116,7 +117,8 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, out_len) < 0) {
+ rhdr, end - rhdr, hs_start, pos - hs_start,
+ out_len) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -192,7 +194,8 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ rhdr, end - rhdr, hs_start, pos - hs_start,
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -413,7 +416,8 @@ static int tls_write_client_key_exchange(struct tlsv1_client *conn,
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ rhdr, end - rhdr, hs_start, pos - hs_start,
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -433,7 +437,7 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
{
u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
size_t rlen, hlen, clen;
- u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
+ u8 hash[100], *hpos;
enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
pos = *msgpos;
@@ -473,6 +477,40 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
hpos = hash;
+#ifdef CONFIG_TLSV12
+ if (conn->rl.tls_version == TLS_VERSION_1_2) {
+ hlen = SHA256_MAC_LEN;
+ if (conn->verify.sha256_cert == NULL ||
+ crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
+ 0) {
+ conn->verify.sha256_cert = NULL;
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify.sha256_cert = NULL;
+
+ /*
+ * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithm,
+ * digest OCTET STRING
+ * }
+ *
+ * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+ *
+ * DER encoded DigestInfo for SHA256 per RFC 3447:
+ * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+ * H
+ */
+ os_memmove(hash + 19, hash, hlen);
+ hlen += 19;
+ os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
+ "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
+ } else {
+#endif /* CONFIG_TLSV12 */
+
if (alg == SIGN_ALG_RSA) {
hlen = MD5_MAC_LEN;
if (conn->verify.md5_cert == NULL ||
@@ -503,8 +541,29 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
if (alg == SIGN_ALG_RSA)
hlen += MD5_MAC_LEN;
+#ifdef CONFIG_TLSV12
+ }
+#endif /* CONFIG_TLSV12 */
+
wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
+#ifdef CONFIG_TLSV12
+ if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+ /*
+ * RFC 5246, 4.7:
+ * TLS v1.2 adds explicit indication of the used signature and
+ * hash algorithms.
+ *
+ * struct {
+ * HashAlgorithm hash;
+ * SignatureAlgorithm signature;
+ * } SignatureAndHashAlgorithm;
+ */
+ *pos++ = TLS_HASH_ALG_SHA256;
+ *pos++ = TLS_SIGN_ALG_RSA;
+ }
+#endif /* CONFIG_TLSV12 */
+
/*
* RFC 2246, 4.7:
* In digital signing, one-way hash functions are used as input for a
@@ -534,7 +593,8 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ rhdr, end - rhdr, hs_start, pos - hs_start,
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -553,17 +613,16 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
u8 **msgpos, u8 *end)
{
- u8 *pos, *rhdr;
size_t rlen;
-
- pos = *msgpos;
+ u8 payload[1];
wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
- rhdr = pos;
- pos += TLS_RECORD_HEADER_LEN;
- *pos = TLS_CHANGE_CIPHER_SPEC;
+
+ payload[0] = TLS_CHANGE_CIPHER_SPEC;
+
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
- rhdr, end - rhdr, 1, &rlen) < 0) {
+ *msgpos, end - *msgpos, payload, sizeof(payload),
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -578,7 +637,7 @@ static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
return -1;
}
- *msgpos = rhdr + rlen;
+ *msgpos += rlen;
return 0;
}
@@ -587,17 +646,30 @@ static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
static int tls_write_client_finished(struct tlsv1_client *conn,
u8 **msgpos, u8 *end)
{
- u8 *pos, *rhdr, *hs_start, *hs_length;
+ u8 *pos, *hs_start;
size_t rlen, hlen;
- u8 verify_data[TLS_VERIFY_DATA_LEN];
+ u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
- pos = *msgpos;
-
wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
/* Encrypted Handshake Message: Finished */
+#ifdef CONFIG_TLSV12
+ if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+ hlen = SHA256_MAC_LEN;
+ if (conn->verify.sha256_client == NULL ||
+ crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
+ < 0) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.sha256_client = NULL;
+ return -1;
+ }
+ conn->verify.sha256_client = NULL;
+ } else {
+#endif /* CONFIG_TLSV12 */
+
hlen = MD5_MAC_LEN;
if (conn->verify.md5_client == NULL ||
crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
@@ -619,43 +691,44 @@ static int tls_write_client_finished(struct tlsv1_client *conn,
return -1;
}
conn->verify.sha1_client = NULL;
+ hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+ }
+#endif /* CONFIG_TLSV12 */
- if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
- "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
- verify_data, TLS_VERIFY_DATA_LEN)) {
+ if (tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "client finished", hash, hlen,
+ verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
- verify_data, TLS_VERIFY_DATA_LEN);
+ verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
- rhdr = pos;
- pos += TLS_RECORD_HEADER_LEN;
/* Handshake */
- hs_start = pos;
+ pos = hs_start = verify_data;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
- /* uint24 length (to be filled) */
- hs_length = pos;
+ /* uint24 length */
+ WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
pos += 3;
- os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
- pos += TLS_VERIFY_DATA_LEN;
- WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+ pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ *msgpos, end - *msgpos, hs_start, pos - hs_start,
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
- pos = rhdr + rlen;
-
- *msgpos = pos;
+ *msgpos += rlen;
return 0;
}
@@ -778,7 +851,8 @@ u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
/* ContentType type */
*pos++ = TLS_CONTENT_TYPE_ALERT;
/* ProtocolVersion version */
- WPA_PUT_BE16(pos, TLS_VERSION);
+ WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
+ TLS_VERSION);
pos += 2;
/* uint16 length (to be filled) */
length = pos;
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index 2f9dd0f..871359a 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -1,6 +1,6 @@
/*
* TLSv1 common routines
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,8 @@
#include "includes.h"
#include "common.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
#include "x509v3.h"
#include "tlsv1_common.h"
@@ -50,7 +52,15 @@ static const struct tls_cipher_suite tls_cipher_suites[] = {
{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
TLS_HASH_SHA },
{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
- TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }
+ TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
+ { TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
+ TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+ { TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
+ TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
+ { TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
+ TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+ { TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
+ TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
};
#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
@@ -202,6 +212,19 @@ int tls_verify_hash_init(struct tls_verify_hash *verify)
tls_verify_hash_free(verify);
return -1;
}
+#ifdef CONFIG_TLSV12
+ verify->sha256_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+ 0);
+ verify->sha256_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+ 0);
+ verify->sha256_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+ 0);
+ if (verify->sha256_client == NULL || verify->sha256_server == NULL ||
+ verify->sha256_cert == NULL) {
+ tls_verify_hash_free(verify);
+ return -1;
+ }
+#endif /* CONFIG_TLSV12 */
return 0;
}
@@ -221,6 +244,14 @@ void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
crypto_hash_update(verify->md5_cert, buf, len);
crypto_hash_update(verify->sha1_cert, buf, len);
}
+#ifdef CONFIG_TLSV12
+ if (verify->sha256_client)
+ crypto_hash_update(verify->sha256_client, buf, len);
+ if (verify->sha256_server)
+ crypto_hash_update(verify->sha256_server, buf, len);
+ if (verify->sha256_cert)
+ crypto_hash_update(verify->sha256_cert, buf, len);
+#endif /* CONFIG_TLSV12 */
}
@@ -238,4 +269,60 @@ void tls_verify_hash_free(struct tls_verify_hash *verify)
verify->sha1_client = NULL;
verify->sha1_server = NULL;
verify->sha1_cert = NULL;
+#ifdef CONFIG_TLSV12
+ crypto_hash_finish(verify->sha256_client, NULL, NULL);
+ crypto_hash_finish(verify->sha256_server, NULL, NULL);
+ crypto_hash_finish(verify->sha256_cert, NULL, NULL);
+ verify->sha256_client = NULL;
+ verify->sha256_server = NULL;
+ verify->sha256_cert = NULL;
+#endif /* CONFIG_TLSV12 */
+}
+
+
+int tls_version_ok(u16 ver)
+{
+ if (ver == TLS_VERSION_1)
+ return 1;
+#ifdef CONFIG_TLSV11
+ if (ver == TLS_VERSION_1_1)
+ return 1;
+#endif /* CONFIG_TLSV11 */
+#ifdef CONFIG_TLSV12
+ if (ver == TLS_VERSION_1_2)
+ return 1;
+#endif /* CONFIG_TLSV12 */
+
+ return 0;
+}
+
+
+const char * tls_version_str(u16 ver)
+{
+ switch (ver) {
+ case TLS_VERSION_1:
+ return "1.0";
+ case TLS_VERSION_1_1:
+ return "1.1";
+ case TLS_VERSION_1_2:
+ return "1.2";
+ }
+
+ return "?";
+}
+
+
+int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
+ const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+#ifdef CONFIG_TLSV12
+ if (ver >= TLS_VERSION_1_2) {
+ tls_prf_sha256(secret, secret_len, label, seed, seed_len,
+ out, outlen);
+ return 0;
+ }
+#endif /* CONFIG_TLSV12 */
+
+ return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
+ outlen);
}
diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h
index 763a4af..027daa4 100644
--- a/src/tls/tlsv1_common.h
+++ b/src/tls/tlsv1_common.h
@@ -1,6 +1,6 @@
/*
* TLSv1 common definitions
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,7 +17,18 @@
#include "crypto/crypto.h"
-#define TLS_VERSION 0x0301 /* TLSv1 */
+#define TLS_VERSION_1 0x0301 /* TLSv1 */
+#define TLS_VERSION_1_1 0x0302 /* TLSv1.1 */
+#define TLS_VERSION_1_2 0x0303 /* TLSv1.2 */
+#ifdef CONFIG_TLSV12
+#define TLS_VERSION TLS_VERSION_1_2
+#else /* CONFIG_TLSV12 */
+#ifdef CONFIG_TLSV11
+#define TLS_VERSION TLS_VERSION_1_1
+#else /* CONFIG_TLSV11 */
+#define TLS_VERSION TLS_VERSION_1
+#endif /* CONFIG_TLSV11 */
+#endif /* CONFIG_TLSV12 */
#define TLS_RANDOM_LEN 32
#define TLS_PRE_MASTER_SECRET_LEN 48
#define TLS_MASTER_SECRET_LEN 48
@@ -82,10 +93,42 @@ enum {
#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038 /* RFC 3268 */
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 /* RFC 3268 */
#define TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A /* RFC 3268 */
+#define TLS_RSA_WITH_NULL_SHA256 0x003B /* RFC 5246 */
+#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C /* RFC 5246 */
+#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D /* RFC 5246 */
+#define TLS_DH_DSS_WITH_AES_128_CBC_SHA256 0x003E /* RFC 5246 */
+#define TLS_DH_RSA_WITH_AES_128_CBC_SHA256 0x003F /* RFC 5246 */
+#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 0x0040 /* RFC 5246 */
+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067 /* RFC 5246 */
+#define TLS_DH_DSS_WITH_AES_256_CBC_SHA256 0x0068 /* RFC 5246 */
+#define TLS_DH_RSA_WITH_AES_256_CBC_SHA256 0x0069 /* RFC 5246 */
+#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 0x006A /* RFC 5246 */
+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B /* RFC 5246 */
+#define TLS_DH_anon_WITH_AES_128_CBC_SHA256 0x006C /* RFC 5246 */
+#define TLS_DH_anon_WITH_AES_256_CBC_SHA256 0x006D /* RFC 5246 */
/* CompressionMethod */
#define TLS_COMPRESSION_NULL 0
+/* HashAlgorithm */
+enum {
+ TLS_HASH_ALG_NONE = 0,
+ TLS_HASH_ALG_MD5 = 1,
+ TLS_HASH_ALG_SHA1 = 2,
+ TLS_HASH_ALG_SHA224 = 3,
+ TLS_HASH_ALG_SHA256 = 4,
+ TLS_HASH_ALG_SHA384 = 5,
+ TLS_HASH_ALG_SHA512 = 6
+};
+
+/* SignatureAlgorithm */
+enum {
+ TLS_SIGN_ALG_ANONYMOUS = 0,
+ TLS_SIGN_ALG_RSA = 1,
+ TLS_SIGN_ALG_DSA = 2,
+ TLS_SIGN_ALG_ECDSA = 3,
+};
+
/* AlertLevel */
#define TLS_ALERT_LEVEL_WARNING 1
#define TLS_ALERT_LEVEL_FATAL 2
@@ -169,7 +212,8 @@ typedef enum {
typedef enum {
TLS_HASH_NULL,
TLS_HASH_MD5,
- TLS_HASH_SHA
+ TLS_HASH_SHA,
+ TLS_HASH_SHA256
} tls_hash;
struct tls_cipher_suite {
@@ -197,10 +241,13 @@ struct tls_cipher_data {
struct tls_verify_hash {
struct crypto_hash *md5_client;
struct crypto_hash *sha1_client;
+ struct crypto_hash *sha256_client;
struct crypto_hash *md5_server;
struct crypto_hash *sha1_server;
+ struct crypto_hash *sha256_server;
struct crypto_hash *md5_cert;
struct crypto_hash *sha1_cert;
+ struct crypto_hash *sha256_cert;
};
@@ -212,5 +259,9 @@ int tls_verify_hash_init(struct tls_verify_hash *verify);
void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
size_t len);
void tls_verify_hash_free(struct tls_verify_hash *verify);
+int tls_version_ok(u16 ver);
+const char * tls_version_str(u16 ver);
+int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
+ const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
#endif /* TLSV1_COMMON_H */
diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c
index aa467ef..d846480 100644
--- a/src/tls/tlsv1_cred.c
+++ b/src/tls/tlsv1_cred.c
@@ -46,7 +46,7 @@ void tlsv1_cred_free(struct tlsv1_credentials *cred)
static int tlsv1_add_cert_der(struct x509_certificate **chain,
const u8 *buf, size_t len)
{
- struct x509_certificate *cert;
+ struct x509_certificate *cert, *p;
char name[128];
cert = x509_certificate_parse(buf, len);
@@ -56,8 +56,20 @@ static int tlsv1_add_cert_der(struct x509_certificate **chain,
return -1;
}
- cert->next = *chain;
- *chain = cert;
+ p = *chain;
+ while (p && p->next)
+ p = p->next;
+ if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) {
+ /*
+ * The new certificate is the issuer of the last certificate in
+ * the chain - add the new certificate to the end.
+ */
+ p->next = cert;
+ } else {
+ /* Add to the beginning of the chain */
+ cert->next = *chain;
+ *chain = cert;
+ }
x509_name_string(&cert->subject, name, sizeof(name));
wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
@@ -232,10 +244,17 @@ static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
if (!end)
return NULL;
} else {
+ const u8 *pos2;
pos += os_strlen(pem_key_begin);
end = search_tag(pem_key_end, pos, key + len - pos);
if (!end)
return NULL;
+ pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos);
+ if (pos2) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key "
+ "format (Proc-Type/DEK-Info)");
+ return NULL;
+ }
}
der = base64_decode(pos, end - pos, &der_len);
diff --git a/src/tls/tlsv1_record.c b/src/tls/tlsv1_record.c
index e811f0e..0314551 100644
--- a/src/tls/tlsv1_record.c
+++ b/src/tls/tlsv1_record.c
@@ -1,6 +1,6 @@
/*
* TLSv1 Record Protocol
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
+#include "crypto/sha256.h"
#include "tlsv1_common.h"
#include "tlsv1_record.h"
@@ -52,6 +53,9 @@ int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
} else if (suite->hash == TLS_HASH_SHA) {
rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
rl->hash_size = SHA1_MAC_LEN;
+ } else if (suite->hash == TLS_HASH_SHA256) {
+ rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA256;
+ rl->hash_size = SHA256_MAC_LEN;
}
data = tls_get_cipher_data(suite->cipher);
@@ -138,10 +142,10 @@ int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
* tlsv1_record_send - TLS record layer: Send a message
* @rl: Pointer to TLS record layer data
* @content_type: Content type (TLS_CONTENT_TYPE_*)
- * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
- * beginning for record layer to fill in; payload filled in after this and
- * extra space in the end for HMAC).
+ * @buf: Buffer for the generated TLS message (needs to have extra space for
+ * header, IV (TLS v1.1), and HMAC)
* @buf_size: Maximum buf size
+ * @payload: Payload to be sent
* @payload_len: Length of the payload
* @out_len: Buffer for returning the used buf length
* Returns: 0 on success, -1 on failure
@@ -150,29 +154,62 @@ int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
* the data using the current write cipher.
*/
int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
- size_t buf_size, size_t payload_len, size_t *out_len)
+ size_t buf_size, const u8 *payload, size_t payload_len,
+ size_t *out_len)
{
- u8 *pos, *ct_start, *length, *payload;
+ u8 *pos, *ct_start, *length, *cpayload;
struct crypto_hash *hmac;
size_t clen;
+ int explicit_iv;
pos = buf;
+ if (pos + TLS_RECORD_HEADER_LEN > buf + buf_size)
+ return -1;
+
/* ContentType type */
ct_start = pos;
*pos++ = content_type;
/* ProtocolVersion version */
- WPA_PUT_BE16(pos, TLS_VERSION);
+ WPA_PUT_BE16(pos, rl->tls_version);
pos += 2;
/* uint16 length */
length = pos;
WPA_PUT_BE16(length, payload_len);
pos += 2;
- /* opaque fragment[TLSPlaintext.length] */
- payload = pos;
+ cpayload = pos;
+ explicit_iv = rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL &&
+ rl->iv_size && rl->tls_version >= TLS_VERSION_1_1;
+ if (explicit_iv) {
+ /* opaque IV[Cipherspec.block_length] */
+ if (pos + rl->iv_size > buf + buf_size)
+ return -1;
+
+ /*
+ * Use random number R per the RFC 4346, 6.2.3.2 CBC Block
+ * Cipher option 2a.
+ */
+
+ if (os_get_random(pos, rl->iv_size))
+ return -1;
+ pos += rl->iv_size;
+ }
+
+ /*
+ * opaque fragment[TLSPlaintext.length]
+ * (opaque content[TLSCompressed.length] in GenericBlockCipher)
+ */
+ if (pos + payload_len > buf + buf_size)
+ return -1;
+ os_memmove(pos, payload, payload_len);
pos += payload_len;
if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+ /*
+ * MAC calculated over seq_num + TLSCompressed.type +
+ * TLSCompressed.version + TLSCompressed.length +
+ * TLSCompressed.fragment
+ */
hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
rl->hash_size);
if (hmac == NULL) {
@@ -182,7 +219,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
}
crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
/* type + version + length + fragment */
- crypto_hash_update(hmac, ct_start, pos - ct_start);
+ crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN);
+ crypto_hash_update(hmac, payload, payload_len);
clen = buf + buf_size - pos;
if (clen < rl->hash_size) {
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
@@ -200,7 +238,7 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
pos, clen);
pos += clen;
if (rl->iv_size) {
- size_t len = pos - payload;
+ size_t len = pos - cpayload;
size_t pad;
pad = (len + 1) % rl->iv_size;
if (pad)
@@ -214,8 +252,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
pos += pad + 1;
}
- if (crypto_cipher_encrypt(rl->write_cbc, payload,
- payload, pos - payload) < 0)
+ if (crypto_cipher_encrypt(rl->write_cbc, cpayload,
+ cpayload, pos - cpayload) < 0)
return -1;
}
@@ -237,7 +275,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
* @out_len: Set to maximum out_data length by caller; used to return the
* length of the used data
* @alert: Buffer for returning an alert value on failure
- * Returns: 0 on success, -1 on failure
+ * Returns: Number of bytes used from in_data on success, 0 if record was not
+ * complete (more data needed), or -1 on failure
*
* This function decrypts the received message, verifies HMAC and TLS record
* layer header.
@@ -250,40 +289,35 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
u8 padlen;
struct crypto_hash *hmac;
u8 len[2], hash[100];
-
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
- in_data, in_len);
+ int force_mac_error = 0;
+ u8 ct;
if (in_len < TLS_RECORD_HEADER_LEN) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu) - "
+ "need more data",
(unsigned long) in_len);
- *alert = TLS_ALERT_DECODE_ERROR;
- return -1;
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+ in_data, in_len);
+ return 0;
}
+ ct = in_data[0];
+ rlen = WPA_GET_BE16(in_data + 3);
wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
- "length %d", in_data[0], in_data[1], in_data[2],
- WPA_GET_BE16(in_data + 3));
-
- if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
- in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
- in_data[0] != TLS_CONTENT_TYPE_ALERT &&
- in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
- in_data[0]);
- *alert = TLS_ALERT_UNEXPECTED_MESSAGE;
- return -1;
- }
-
- if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
+ "length %d", ct, in_data[1], in_data[2], (int) rlen);
+
+ /*
+ * TLS v1.0 and v1.1 RFCs were not exactly clear on the use of the
+ * protocol version in record layer. As such, accept any {03,xx} value
+ * to remain compatible with existing implementations.
+ */
+ if (in_data[1] != 0x03) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
- "%d.%d", in_data[1], in_data[2]);
+ "%u.%u", in_data[1], in_data[2]);
*alert = TLS_ALERT_PROTOCOL_VERSION;
return -1;
}
- rlen = WPA_GET_BE16(in_data + 3);
-
/* TLSCiphertext must not be more than 2^14+2048 bytes */
if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
@@ -299,7 +333,19 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
"(rlen=%lu > in_len=%lu)",
(unsigned long) rlen, (unsigned long) in_len);
- *alert = TLS_ALERT_DECODE_ERROR;
+ return 0;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+ in_data, rlen);
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE &&
+ ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
+ ct != TLS_CONTENT_TYPE_ALERT &&
+ ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Ignore record with unknown "
+ "content type 0x%x", ct);
+ *alert = TLS_ALERT_UNEXPECTED_MESSAGE;
return -1;
}
@@ -312,58 +358,86 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
return -1;
}
- os_memcpy(out_data, in_data, in_len);
- *out_len = in_len;
-
if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
- if (crypto_cipher_decrypt(rl->read_cbc, out_data,
+ size_t plen;
+ if (crypto_cipher_decrypt(rl->read_cbc, in_data,
out_data, in_len) < 0) {
*alert = TLS_ALERT_DECRYPTION_FAILED;
return -1;
}
+ plen = in_len;
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
+ "data", out_data, plen);
+
if (rl->iv_size) {
- if (in_len == 0) {
+ /*
+ * TLS v1.0 defines different alert values for various
+ * failures. That may information to aid in attacks, so
+ * use the same bad_record_mac alert regardless of the
+ * issues.
+ *
+ * In addition, instead of returning immediately on
+ * error, run through the MAC check to make timing
+ * attacks more difficult.
+ */
+
+ if (rl->tls_version >= TLS_VERSION_1_1) {
+ /* Remove opaque IV[Cipherspec.block_length] */
+ if (plen < rl->iv_size) {
+ wpa_printf(MSG_DEBUG, "TLSv1.1: Not "
+ "enough room for IV");
+ force_mac_error = 1;
+ goto check_mac;
+ }
+ os_memmove(out_data, out_data + rl->iv_size,
+ plen - rl->iv_size);
+ plen -= rl->iv_size;
+ }
+
+ /* Verify and remove padding */
+ if (plen == 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
" (no pad)");
- *alert = TLS_ALERT_DECODE_ERROR;
- return -1;
+ force_mac_error = 1;
+ goto check_mac;
}
- padlen = out_data[in_len - 1];
- if (padlen >= in_len) {
+ padlen = out_data[plen - 1];
+ if (padlen >= plen) {
wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
- "length (%u, in_len=%lu) in "
+ "length (%u, plen=%lu) in "
"received record",
- padlen, (unsigned long) in_len);
- *alert = TLS_ALERT_DECRYPTION_FAILED;
- return -1;
+ padlen, (unsigned long) plen);
+ force_mac_error = 1;
+ goto check_mac;
}
- for (i = in_len - padlen; i < in_len; i++) {
+ for (i = plen - padlen - 1; i < plen - 1; i++) {
if (out_data[i] != padlen) {
wpa_hexdump(MSG_DEBUG,
"TLSv1: Invalid pad in "
"received record",
- out_data + in_len - padlen,
- padlen);
- *alert = TLS_ALERT_DECRYPTION_FAILED;
- return -1;
+ out_data + plen - padlen -
+ 1, padlen + 1);
+ force_mac_error = 1;
+ goto check_mac;
}
}
- *out_len -= padlen + 1;
- }
+ plen -= padlen + 1;
- wpa_hexdump(MSG_MSGDUMP,
- "TLSv1: Record Layer - Decrypted data",
- out_data, in_len);
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - "
+ "Decrypted data with IV and padding "
+ "removed", out_data, plen);
+ }
- if (*out_len < rl->hash_size) {
+ check_mac:
+ if (plen < rl->hash_size) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
"hash value");
- *alert = TLS_ALERT_INTERNAL_ERROR;
+ *alert = TLS_ALERT_BAD_RECORD_MAC;
return -1;
}
- *out_len -= rl->hash_size;
+ plen -= rl->hash_size;
hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
rl->hash_size);
@@ -377,22 +451,30 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
/* type + version + length + fragment */
crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
- WPA_PUT_BE16(len, *out_len);
+ WPA_PUT_BE16(len, plen);
crypto_hash_update(hmac, len, 2);
- crypto_hash_update(hmac, out_data, *out_len);
+ crypto_hash_update(hmac, out_data, plen);
hlen = sizeof(hash);
if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
"to calculate HMAC");
+ *alert = TLS_ALERT_INTERNAL_ERROR;
return -1;
}
if (hlen != rl->hash_size ||
- os_memcmp(hash, out_data + *out_len, hlen) != 0) {
+ os_memcmp(hash, out_data + plen, hlen) != 0 ||
+ force_mac_error) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
- "received message");
+ "received message (force_mac_error=%d)",
+ force_mac_error);
*alert = TLS_ALERT_BAD_RECORD_MAC;
return -1;
}
+
+ *out_len = plen;
+ } else {
+ os_memcpy(out_data, in_data, in_len);
+ *out_len = in_len;
}
/* TLSCompressed must not be more than 2^14+1024 bytes */
@@ -405,5 +487,5 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
- return 0;
+ return TLS_RECORD_HEADER_LEN + rlen;
}
diff --git a/src/tls/tlsv1_record.h b/src/tls/tlsv1_record.h
index 9c7c0a4..9eb9bfd 100644
--- a/src/tls/tlsv1_record.h
+++ b/src/tls/tlsv1_record.h
@@ -1,6 +1,6 @@
/*
* TLSv1 Record Protocol
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,7 +17,7 @@
#include "crypto/crypto.h"
-#define TLS_MAX_WRITE_MAC_SECRET_LEN 20
+#define TLS_MAX_WRITE_MAC_SECRET_LEN 32
#define TLS_MAX_WRITE_KEY_LEN 32
#define TLS_MAX_IV_LEN 16
#define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
@@ -35,6 +35,8 @@ enum {
};
struct tlsv1_record_layer {
+ u16 tls_version;
+
u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
u8 write_key[TLS_MAX_WRITE_KEY_LEN];
@@ -66,7 +68,8 @@ int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
- size_t buf_size, size_t payload_len, size_t *out_len);
+ size_t buf_size, const u8 *payload, size_t payload_len,
+ size_t *out_len);
int tlsv1_record_receive(struct tlsv1_record_layer *rl,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t *out_len, u8 *alert);
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 6a61235..96e160c 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -1,6 +1,6 @@
/*
- * TLSv1 server (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -49,7 +49,8 @@ int tlsv1_server_derive_keys(struct tlsv1_server *conn,
os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
TLS_RANDOM_LEN);
- if (tls_prf(pre_master_secret, pre_master_secret_len,
+ if (tls_prf(conn->rl.tls_version,
+ pre_master_secret, pre_master_secret_len,
"master secret", seed, 2 * TLS_RANDOM_LEN,
conn->master_secret, TLS_MASTER_SECRET_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
@@ -64,7 +65,8 @@ int tlsv1_server_derive_keys(struct tlsv1_server *conn,
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
conn->rl.iv_size);
- if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ if (tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
"key expansion", seed, 2 * TLS_RANDOM_LEN,
key_block, key_block_len)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
@@ -115,6 +117,7 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
const u8 *pos, *end;
u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
size_t in_msg_len;
+ int used;
if (in_data == NULL || in_len == 0) {
wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
@@ -130,13 +133,21 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
/* Each received packet may include multiple records */
while (pos < end) {
in_msg_len = in_len;
- if (tlsv1_record_receive(&conn->rl, pos, end - pos,
- in_msg, &in_msg_len, &alert)) {
+ used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+ in_msg, &in_msg_len, &alert);
+ if (used < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
"record failed");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
goto failed;
}
+ if (used == 0) {
+ /* need more data */
+ wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+ "yet supported");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ goto failed;
+ }
ct = pos[0];
in_pos = in_msg;
@@ -152,7 +163,7 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
in_pos += in_msg_len;
}
- pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ pos += used;
}
os_free(in_msg);
@@ -201,10 +212,8 @@ int tlsv1_server_encrypt(struct tlsv1_server *conn,
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
in_data, in_len);
- os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
-
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
- out_data, out_len, in_len, &rlen) < 0) {
+ out_data, out_len, in_data, in_len, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -232,8 +241,8 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
u8 *out_data, size_t out_len)
{
const u8 *in_end, *pos;
- int res;
- u8 alert, *out_end, *out_pos;
+ int used;
+ u8 alert, *out_end, *out_pos, ct;
size_t olen;
pos = in_data;
@@ -242,7 +251,46 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
out_end = out_data + out_len;
while (pos < in_end) {
- if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+ ct = pos[0];
+ olen = out_end - out_pos;
+ used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+ out_pos, &olen, &alert);
+ if (used < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
+ "failed");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ return -1;
+ }
+ if (used == 0) {
+ /* need more data */
+ wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+ "yet supported");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ return -1;
+ }
+
+ if (ct == TLS_CONTENT_TYPE_ALERT) {
+ if (olen < 2) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+ "underflow");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+ out_pos[0], out_pos[1]);
+ if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+ /* Continue processing */
+ pos += used;
+ continue;
+ }
+
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ out_pos[1]);
+ return -1;
+ }
+
+ if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
"0x%x", pos[0]);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -250,15 +298,6 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
return -1;
}
- olen = out_end - out_pos;
- res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
- out_pos, &olen, &alert);
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
- "failed");
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
- return -1;
- }
out_pos += olen;
if (out_pos > out_end) {
wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -268,7 +307,7 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
return -1;
}
- pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ pos += used;
}
return out_pos - out_data;
@@ -412,7 +451,8 @@ int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
TLS_RANDOM_LEN);
}
- return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ return tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
}
diff --git a/src/tls/tlsv1_server.h b/src/tls/tlsv1_server.h
index 00c536c..daa4353 100644
--- a/src/tls/tlsv1_server.h
+++ b/src/tls/tlsv1_server.h
@@ -1,6 +1,6 @@
/*
- * TLSv1 server (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index fd74436..443c028 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -1,6 +1,6 @@
/*
* TLSv1 server - read handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
+#include "crypto/sha256.h"
#include "crypto/tls.h"
#include "x509v3.h"
#include "tlsv1_common.h"
@@ -85,15 +86,30 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
conn->client_version = WPA_GET_BE16(pos);
wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
conn->client_version >> 8, conn->client_version & 0xff);
- if (conn->client_version < TLS_VERSION) {
+ if (conn->client_version < TLS_VERSION_1) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
- "ClientHello");
+ "ClientHello %u.%u",
+ conn->client_version >> 8,
+ conn->client_version & 0xff);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_PROTOCOL_VERSION);
return -1;
}
pos += 2;
+ if (TLS_VERSION == TLS_VERSION_1)
+ conn->rl.tls_version = TLS_VERSION_1;
+#ifdef CONFIG_TLSV12
+ else if (conn->client_version >= TLS_VERSION_1_2)
+ conn->rl.tls_version = TLS_VERSION_1_2;
+#endif /* CONFIG_TLSV12 */
+ else if (conn->client_version > TLS_VERSION_1_1)
+ conn->rl.tls_version = TLS_VERSION_1_1;
+ else
+ conn->rl.tls_version = conn->client_version;
+ wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
+ tls_version_str(conn->rl.tls_version));
+
/* Random random */
if (end - pos < TLS_RANDOM_LEN)
goto decode_error;
@@ -483,6 +499,14 @@ static int tls_process_client_key_exchange_rsa(
encr_len = WPA_GET_BE16(pos);
pos += 2;
+ if (pos + encr_len > end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange "
+ "format: encr_len=%u left=%u",
+ encr_len, (unsigned int) (end - pos));
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
outbuflen = outlen = end - pos;
out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
@@ -512,21 +536,21 @@ static int tls_process_client_key_exchange_rsa(
*/
if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
- pos, end - pos,
+ pos, encr_len,
out, &outlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
- "PreMasterSecret (encr_len=%d outlen=%lu)",
- (int) (end - pos), (unsigned long) outlen);
+ "PreMasterSecret (encr_len=%u outlen=%lu)",
+ encr_len, (unsigned long) outlen);
use_random = 1;
}
- if (outlen != TLS_PRE_MASTER_SECRET_LEN) {
+ if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
"length %lu", (unsigned long) outlen);
use_random = 1;
}
- if (WPA_GET_BE16(out) != conn->client_version) {
+ if (!use_random && WPA_GET_BE16(out) != conn->client_version) {
wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
"ClientKeyExchange does not match with version in "
"ClientHello");
@@ -822,6 +846,47 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
hpos = hash;
+#ifdef CONFIG_TLSV12
+ if (conn->rl.tls_version == TLS_VERSION_1_2) {
+ /*
+ * RFC 5246, 4.7:
+ * TLS v1.2 adds explicit indication of the used signature and
+ * hash algorithms.
+ *
+ * struct {
+ * HashAlgorithm hash;
+ * SignatureAlgorithm signature;
+ * } SignatureAndHashAlgorithm;
+ */
+ if (end - pos < 2) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ if (pos[0] != TLS_HASH_ALG_SHA256 ||
+ pos[1] != TLS_SIGN_ALG_RSA) {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/"
+ "signature(%u) algorithm",
+ pos[0], pos[1]);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos += 2;
+
+ hlen = SHA256_MAC_LEN;
+ if (conn->verify.sha256_cert == NULL ||
+ crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
+ 0) {
+ conn->verify.sha256_cert = NULL;
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify.sha256_cert = NULL;
+ } else {
+#endif /* CONFIG_TLSV12 */
+
if (alg == SIGN_ALG_RSA) {
hlen = MD5_MAC_LEN;
if (conn->verify.md5_cert == NULL ||
@@ -852,6 +917,10 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
if (alg == SIGN_ALG_RSA)
hlen += MD5_MAC_LEN;
+#ifdef CONFIG_TLSV12
+ }
+#endif /* CONFIG_TLSV12 */
+
wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
if (end - pos < 2) {
@@ -891,6 +960,41 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
buf, buflen);
+#ifdef CONFIG_TLSV12
+ if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+ /*
+ * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithm,
+ * digest OCTET STRING
+ * }
+ *
+ * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+ *
+ * DER encoded DigestInfo for SHA256 per RFC 3447:
+ * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+ * H
+ */
+ if (buflen >= 19 + 32 &&
+ os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
+ "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
+ {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = "
+ "SHA-256");
+ os_memmove(buf, buf + 19, buflen - 19);
+ buflen -= 19;
+ } else {
+ wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized "
+ "DigestInfo");
+ os_free(buf);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECRYPT_ERROR);
+ return -1;
+ }
+ }
+#endif /* CONFIG_TLSV12 */
+
if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
"CertificateVerify - did not match with calculated "
@@ -1022,6 +1126,21 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
pos, TLS_VERIFY_DATA_LEN);
+#ifdef CONFIG_TLSV12
+ if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+ hlen = SHA256_MAC_LEN;
+ if (conn->verify.sha256_client == NULL ||
+ crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
+ < 0) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.sha256_client = NULL;
+ return -1;
+ }
+ conn->verify.sha256_client = NULL;
+ } else {
+#endif /* CONFIG_TLSV12 */
+
hlen = MD5_MAC_LEN;
if (conn->verify.md5_client == NULL ||
crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
@@ -1043,9 +1162,15 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
return -1;
}
conn->verify.sha1_client = NULL;
+ hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+ }
+#endif /* CONFIG_TLSV12 */
- if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
- "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+ if (tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "client finished", hash, hlen,
verify_data, TLS_VERIFY_DATA_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index e89e52e..0ca3b23 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -1,6 +1,6 @@
/*
* TLSv1 server - write handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
+#include "crypto/sha256.h"
#include "crypto/tls.h"
#include "crypto/random.h"
#include "x509v3.h"
@@ -87,7 +88,7 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
pos += 3;
/* body - ServerHello */
/* ProtocolVersion server_version */
- WPA_PUT_BE16(pos, TLS_VERSION);
+ WPA_PUT_BE16(pos, conn->rl.tls_version);
pos += 2;
/* Random random: uint32 gmt_unix_time, opaque random_bytes */
os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
@@ -143,7 +144,8 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ rhdr, end - rhdr, hs_start, pos - hs_start,
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -227,7 +229,8 @@ static int tls_write_server_certificate(struct tlsv1_server *conn,
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ rhdr, end - rhdr, hs_start, pos - hs_start,
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -418,7 +421,8 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ rhdr, end - rhdr, hs_start, pos - hs_start,
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -483,7 +487,8 @@ static int tls_write_server_certificate_request(struct tlsv1_server *conn,
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ rhdr, end - rhdr, hs_start, pos - hs_start,
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -502,40 +507,35 @@ static int tls_write_server_certificate_request(struct tlsv1_server *conn,
static int tls_write_server_hello_done(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
- u8 *pos, *rhdr, *hs_start, *hs_length;
+ u8 *pos;
size_t rlen;
-
- pos = *msgpos;
+ u8 payload[4];
wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
- rhdr = pos;
- pos += TLS_RECORD_HEADER_LEN;
/* opaque fragment[TLSPlaintext.length] */
/* Handshake */
- hs_start = pos;
+ pos = payload;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
- /* uint24 length (to be filled) */
- hs_length = pos;
+ /* uint24 length */
+ WPA_PUT_BE24(pos, 0);
pos += 3;
/* body - ServerHelloDone (empty) */
- WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ *msgpos, end - *msgpos, payload, pos - payload,
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
- pos = rhdr + rlen;
- tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+ tls_verify_hash_add(&conn->verify, payload, pos - payload);
- *msgpos = pos;
+ *msgpos += rlen;
return 0;
}
@@ -544,17 +544,16 @@ static int tls_write_server_hello_done(struct tlsv1_server *conn,
static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
- u8 *pos, *rhdr;
size_t rlen;
-
- pos = *msgpos;
+ u8 payload[1];
wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
- rhdr = pos;
- pos += TLS_RECORD_HEADER_LEN;
- *pos = TLS_CHANGE_CIPHER_SPEC;
+
+ payload[0] = TLS_CHANGE_CIPHER_SPEC;
+
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
- rhdr, end - rhdr, 1, &rlen) < 0) {
+ *msgpos, end - *msgpos, payload, sizeof(payload),
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
@@ -569,7 +568,7 @@ static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
return -1;
}
- *msgpos = rhdr + rlen;
+ *msgpos += rlen;
return 0;
}
@@ -578,9 +577,9 @@ static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
static int tls_write_server_finished(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
- u8 *pos, *rhdr, *hs_start, *hs_length;
+ u8 *pos, *hs_start;
size_t rlen, hlen;
- u8 verify_data[TLS_VERIFY_DATA_LEN];
+ u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
pos = *msgpos;
@@ -589,6 +588,21 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
/* Encrypted Handshake Message: Finished */
+#ifdef CONFIG_TLSV12
+ if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+ hlen = SHA256_MAC_LEN;
+ if (conn->verify.sha256_server == NULL ||
+ crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+ < 0) {
+ conn->verify.sha256_server = NULL;
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify.sha256_server = NULL;
+ } else {
+#endif /* CONFIG_TLSV12 */
+
hlen = MD5_MAC_LEN;
if (conn->verify.md5_server == NULL ||
crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
@@ -610,43 +624,44 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
return -1;
}
conn->verify.sha1_server = NULL;
+ hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+ }
+#endif /* CONFIG_TLSV12 */
- if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
- "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
- verify_data, TLS_VERIFY_DATA_LEN)) {
+ if (tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "server finished", hash, hlen,
+ verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
- verify_data, TLS_VERIFY_DATA_LEN);
+ verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
- rhdr = pos;
- pos += TLS_RECORD_HEADER_LEN;
/* Handshake */
- hs_start = pos;
+ pos = hs_start = verify_data;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
- /* uint24 length (to be filled) */
- hs_length = pos;
+ /* uint24 length */
+ WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
pos += 3;
- os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
pos += TLS_VERIFY_DATA_LEN;
- WPA_PUT_BE24(hs_length, pos - hs_length - 3);
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ *msgpos, end - *msgpos, hs_start, pos - hs_start,
+ &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
- pos = rhdr + rlen;
-
- *msgpos = pos;
+ *msgpos += rlen;
return 0;
}
@@ -771,7 +786,8 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
/* ContentType type */
*pos++ = TLS_CONTENT_TYPE_ALERT;
/* ProtocolVersion version */
- WPA_PUT_BE16(pos, TLS_VERSION);
+ WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
+ TLS_VERSION);
pos += 2;
/* uint16 length (to be filled) */
length = pos;
diff --git a/src/utils/base64.c b/src/utils/base64.c
index 155bfce..fb1224b 100644
--- a/src/utils/base64.c
+++ b/src/utils/base64.c
@@ -1,6 +1,6 @@
/*
* Base64 encoding/decoding (RFC1341)
- * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -103,8 +103,9 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
unsigned char * base64_decode(const unsigned char *src, size_t len,
size_t *out_len)
{
- unsigned char dtable[256], *out, *pos, in[4], block[4], tmp;
+ unsigned char dtable[256], *out, *pos, block[4], tmp;
size_t i, count, olen;
+ int pad = 0;
os_memset(dtable, 0x80, 256);
for (i = 0; i < sizeof(base64_table) - 1; i++)
@@ -131,7 +132,8 @@ unsigned char * base64_decode(const unsigned char *src, size_t len,
if (tmp == 0x80)
continue;
- in[count] = src[i];
+ if (src[i] == '=')
+ pad++;
block[count] = tmp;
count++;
if (count == 4) {
@@ -139,16 +141,21 @@ unsigned char * base64_decode(const unsigned char *src, size_t len,
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
+ if (pad) {
+ if (pad == 1)
+ pos--;
+ else if (pad == 2)
+ pos -= 2;
+ else {
+ /* Invalid padding */
+ os_free(out);
+ return NULL;
+ }
+ break;
+ }
}
}
- if (pos > out) {
- if (in[2] == '=')
- pos -= 2;
- else if (in[3] == '=')
- pos--;
- }
-
*out_len = pos - out;
return out;
}
diff --git a/src/utils/edit.c b/src/utils/edit.c
index 8f9e4ed..c5b17ac 100644
--- a/src/utils/edit.c
+++ b/src/utils/edit.c
@@ -1,6 +1,6 @@
/*
* Command line editing and history
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,6 +24,8 @@
static char cmdbuf[CMD_BUF_LEN];
static int cmdbuf_pos = 0;
static int cmdbuf_len = 0;
+static char currbuf[CMD_BUF_LEN];
+static int currbuf_valid = 0;
#define HISTORY_MAX 100
@@ -231,18 +233,22 @@ static void history_prev(void)
if (history_curr ==
dl_list_first(&history_list, struct edit_history, list)) {
- cmdbuf[cmdbuf_len] = '\0';
- history_add(cmdbuf);
+ if (!currbuf_valid) {
+ cmdbuf[cmdbuf_len] = '\0';
+ os_memcpy(currbuf, cmdbuf, cmdbuf_len + 1);
+ currbuf_valid = 1;
+ history_use();
+ return;
+ }
}
- history_use();
-
if (history_curr ==
dl_list_last(&history_list, struct edit_history, list))
return;
history_curr = dl_list_entry(history_curr->list.next,
struct edit_history, list);
+ history_use();
}
@@ -250,8 +256,16 @@ static void history_next(void)
{
if (history_curr == NULL ||
history_curr ==
- dl_list_first(&history_list, struct edit_history, list))
+ dl_list_first(&history_list, struct edit_history, list)) {
+ if (currbuf_valid) {
+ currbuf_valid = 0;
+ edit_clear_line();
+ cmdbuf_len = cmdbuf_pos = os_strlen(currbuf);
+ os_memcpy(cmdbuf, currbuf, cmdbuf_len);
+ edit_redraw();
+ }
return;
+ }
history_curr = dl_list_entry(history_curr->list.prev,
struct edit_history, list);
@@ -309,6 +323,8 @@ static void history_debug_dump(void)
printf("\r");
dl_list_for_each_reverse(h, &history_list, struct edit_history, list)
printf("%s%s\n", h == history_curr ? "[C]" : "", h->str);
+ if (currbuf_valid)
+ printf("{%s}\n", currbuf);
edit_redraw();
}
@@ -1104,6 +1120,7 @@ int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
void *ctx, const char *history_file)
{
+ currbuf[0] = '\0';
dl_list_init(&history_list);
history_curr = NULL;
if (history_file)
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index 1228f24..a656bf8 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -144,7 +144,7 @@ void eloop_unregister_sock(int sock, eloop_event_type type);
* Returns: 0 on success, -1 on failure
*
* Register an event handler for the given event. This function is used to
- * register eloop implementation specific events which are mainly targetted for
+ * register eloop implementation specific events which are mainly targeted for
* operating system specific code (driver interface and l2_packet) since the
* portable code will not be able to use such an OS-specific call. The handler
* function will be called whenever the event is triggered. The handler
diff --git a/src/utils/includes.h b/src/utils/includes.h
index 63b5c23..cf2a42b 100644
--- a/src/utils/includes.h
+++ b/src/utils/includes.h
@@ -34,7 +34,6 @@
#include <errno.h>
#endif /* _WIN32_WCE */
#include <ctype.h>
-#include <time.h>
#ifndef CONFIG_TI_COMPILER
#ifndef _MSC_VER
diff --git a/src/utils/list.h b/src/utils/list.h
index ded7846..c8dccee 100644
--- a/src/utils/list.h
+++ b/src/utils/list.h
@@ -95,4 +95,7 @@ static inline unsigned int dl_list_len(struct dl_list *list)
&item->member != (list); \
item = dl_list_entry(item->member.prev, type, member))
+#define DEFINE_DL_LIST(name) \
+ struct dl_list name = { &(name), &(name) }
+
#endif /* LIST_H */
diff --git a/src/utils/os.h b/src/utils/os.h
index f4723d8..f69478a 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -70,6 +70,16 @@ int os_get_time(struct os_time *t);
int os_mktime(int year, int month, int day, int hour, int min, int sec,
os_time_t *t);
+struct os_tm {
+ int sec; /* 0..59 or 60 for leap seconds */
+ int min; /* 0..59 */
+ int hour; /* 0..23 */
+ int day; /* 1..31 */
+ int month; /* 1..12 */
+ int year; /* Four digit year */
+};
+
+int os_gmtime(os_time_t t, struct os_tm *tm);
/**
* os_daemonize - Run in the background (detach from the controlling terminal)
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index 5260e23..8024a30 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -70,6 +70,24 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec,
}
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+ struct tm *tm2;
+ time_t t2 = t;
+
+ tm2 = gmtime(&t2);
+ if (tm2 == NULL)
+ return -1;
+ tm->sec = tm2->tm_sec;
+ tm->min = tm2->tm_min;
+ tm->hour = tm2->tm_hour;
+ tm->day = tm2->tm_mday;
+ tm->month = tm2->tm_mon + 1;
+ tm->year = tm2->tm_year + 1900;
+ return 0;
+}
+
+
int os_daemonize(const char *pid_file)
{
if (daemon(0, 0)) {
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
index bab8f17..3fbb777 100644
--- a/src/utils/os_none.c
+++ b/src/utils/os_none.c
@@ -38,6 +38,11 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec,
return -1;
}
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+ return -1;
+}
+
int os_daemonize(const char *pid_file)
{
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 4e11758..9b16b33 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -14,6 +14,8 @@
#include "includes.h"
+#include <time.h>
+
#ifdef ANDROID
#include <linux/capability.h>
#include <linux/prctl.h>
@@ -25,9 +27,9 @@
#ifdef WPA_TRACE
#include "common.h"
-#include "list.h"
#include "wpa_debug.h"
#include "trace.h"
+#include "list.h"
static struct dl_list alloc_list;
@@ -104,6 +106,24 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec,
}
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+ struct tm *tm2;
+ time_t t2 = t;
+
+ tm2 = gmtime(&t2);
+ if (tm2 == NULL)
+ return -1;
+ tm->sec = tm2->tm_sec;
+ tm->min = tm2->tm_min;
+ tm->hour = tm2->tm_hour;
+ tm->day = tm2->tm_mday;
+ tm->month = tm2->tm_mon + 1;
+ tm->year = tm2->tm_year + 1900;
+ return 0;
+}
+
+
#ifdef __APPLE__
#include <fcntl.h>
static int os_daemon(int nochdir, int noclose)
diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c
index 0740964..51bd545 100644
--- a/src/utils/os_win32.c
+++ b/src/utils/os_win32.c
@@ -13,6 +13,7 @@
*/
#include "includes.h"
+#include <time.h>
#include <winsock2.h>
#include <wincrypt.h>
@@ -92,6 +93,24 @@ int os_mktime(int year, int month, int day, int hour, int min, int sec,
}
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+ struct tm *tm2;
+ time_t t2 = t;
+
+ tm2 = gmtime(&t2);
+ if (tm2 == NULL)
+ return -1;
+ tm->sec = tm2->tm_sec;
+ tm->min = tm2->tm_min;
+ tm->hour = tm2->tm_hour;
+ tm->day = tm2->tm_mday;
+ tm->month = tm2->tm_mon + 1;
+ tm->year = tm2->tm_year + 1900;
+ return 0;
+}
+
+
int os_daemonize(const char *pid_file)
{
/* TODO */
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
index bf9f04a..c36193e 100644
--- a/src/utils/pcsc_funcs.c
+++ b/src/utils/pcsc_funcs.c
@@ -812,7 +812,7 @@ static int scard_get_record_len(struct scard_data *scard, unsigned char recnum,
wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
buf, blen);
- if (blen < 2 || buf[0] != 0x6c) {
+ if (blen < 2 || (buf[0] != 0x6c && buf[0] != 0x67)) {
wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
"length determination");
return -1;
diff --git a/src/utils/radiotap.h b/src/utils/radiotap.h
index 508264c..137288f 100644
--- a/src/utils/radiotap.h
+++ b/src/utils/radiotap.h
@@ -238,5 +238,6 @@ enum ieee80211_radiotap_type {
* retries */
#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
+#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ACK */
#endif /* IEEE80211_RADIOTAP_H */
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 0588fc6..5b56d83 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -34,7 +34,7 @@ int wpa_debug_timestamp = 0;
#ifndef ANDROID_LOG_NAME
#define ANDROID_LOG_NAME "wpa_supplicant"
-#endif
+#endif /* ANDROID_LOG_NAME */
void android_printf(int level, char *format, ...)
{
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index ae36afe..64ada57 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -136,7 +136,7 @@ void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
static inline void wpa_hexdump_buf_key(int level, const char *title,
const struct wpabuf *buf)
{
- wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : 0,
+ wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL,
buf ? wpabuf_len(buf) : 0);
}
diff --git a/src/wps/upnp_xml.c b/src/wps/upnp_xml.c
index b1b1e2b..a9958ee 100644
--- a/src/wps/upnp_xml.c
+++ b/src/wps/upnp_xml.c
@@ -75,8 +75,8 @@
* Note that angle brackets present in the original data must have been encoded
* as &lt; and &gt; so they will not trouble us.
*/
-static int xml_next_tag(const char *in, const char **out,
- const char **out_tagname, const char **end)
+int xml_next_tag(const char *in, const char **out,
+ const char **out_tagname, const char **end)
{
while (*in && *in != '<')
in++;
diff --git a/src/wps/upnp_xml.h b/src/wps/upnp_xml.h
index 62dbe60..616af3d 100644
--- a/src/wps/upnp_xml.h
+++ b/src/wps/upnp_xml.h
@@ -16,6 +16,8 @@
void xml_data_encode(struct wpabuf *buf, const char *data, int len);
void xml_add_tagged_data(struct wpabuf *buf, const char *tag,
const char *data);
+int xml_next_tag(const char *in, const char **out,
+ const char **out_tagname, const char **end);
char * xml_get_first_item(const char *doc, const char *item);
struct wpabuf * xml_get_base64_item(const char *data, const char *name,
enum http_reply_code *ret);
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 5c8c25f..2ba3d4b 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -67,12 +67,11 @@ struct wps_data * wps_init(const struct wps_config *cfg)
/* Use special PIN '00000000' for PBC */
data->dev_pw_id = DEV_PW_PUSHBUTTON;
os_free(data->dev_password);
- data->dev_password = os_malloc(8);
+ data->dev_password = (u8 *) os_strdup("00000000");
if (data->dev_password == NULL) {
os_free(data);
return NULL;
}
- os_memset(data->dev_password, '0', 8);
data->dev_password_len = 8;
}
@@ -355,6 +354,19 @@ const u8 * wps_get_uuid_e(const struct wpabuf *msg)
/**
+ * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0
+ */
+int wps_is_20(const struct wpabuf *msg)
+{
+ struct wps_parse_attr attr;
+
+ if (msg == NULL || wps_parse_msg(msg, &attr) < 0)
+ return 0;
+ return attr.version2 != NULL;
+}
+
+
+/**
* wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
* @req_type: Value for Request Type attribute
* Returns: WPS IE or %NULL on failure
@@ -443,7 +455,6 @@ struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
const u8 *req_dev_types)
{
struct wpabuf *ie;
- u16 methods = 0;
wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
@@ -451,35 +462,9 @@ struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
if (ie == NULL)
return NULL;
- methods |= WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
- /*
- * TODO: Should figure out whether this device has a physical or
- * virtual pushbutton.
- */
- methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
-#endif /* CONFIG_WPS2 */
-
- /*
- * TODO: Should figure out whether this Probe Request was triggered
- * using physical or virtual display. Also, if the device has a PIN on
- * a label, that should be indicated here.
- */
- methods |= WPS_CONFIG_DISPLAY |
-#ifdef CONFIG_WPS2
- WPS_CONFIG_VIRT_DISPLAY |
-#endif /* CONFIG_WPS2 */
- WPS_CONFIG_KEYPAD;
-#ifdef CONFIG_WPS_UFD
- methods |= WPS_CONFIG_USBA;
-#endif /* CONFIG_WPS_UFD */
-#ifdef CONFIG_WPS_NFC
- methods |= WPS_CONFIG_NFC_INTERFACE;
-#endif /* CONFIG_WPS_NFC */
-
if (wps_build_version(ie) ||
wps_build_req_type(ie, req_type) ||
- wps_build_config_methods(ie, methods) ||
+ wps_build_config_methods(ie, dev->config_methods) ||
wps_build_uuid_e(ie, uuid) ||
wps_build_primary_dev_type(dev, ie) ||
wps_build_rf_bands(dev, ie) ||
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 3e4c218..4986881 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -99,6 +99,7 @@ struct wps_device_data {
u8 num_sec_dev_types;
u32 os_version;
u8 rf_bands;
+ u16 config_methods;
struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
int p2p;
@@ -239,6 +240,7 @@ int wps_ap_priority_compar(const struct wpabuf *wps_a,
int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
int ver1_compat);
const u8 * wps_get_uuid_e(const struct wpabuf *msg);
+int wps_is_20(const struct wpabuf *msg);
struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
struct wpabuf * wps_build_assoc_resp_ie(void);
@@ -782,6 +784,7 @@ int wps_registrar_wps_cancel(struct wps_registrar *reg);
int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
int wps_registrar_button_pushed(struct wps_registrar *reg,
const u8 *p2p_dev_addr);
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e);
void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
const struct wpabuf *wps_data,
int p2p_wildcard);
@@ -791,6 +794,9 @@ int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
int wps_registrar_config_ap(struct wps_registrar *reg,
struct wps_credential *cred);
+int wps_build_credential_wrap(struct wpabuf *msg,
+ const struct wps_credential *cred);
+
unsigned int wps_pin_checksum(unsigned int pin);
unsigned int wps_pin_valid(unsigned int pin);
unsigned int wps_generate_pin(void);
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index 7b462d3..55b5573 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
@@ -557,7 +557,9 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
{
const u8 *pos, *end;
u16 type, len;
+#ifdef WPS_WORKAROUNDS
u16 prev_type = 0;
+#endif /* WPS_WORKAROUNDS */
os_memset(attr, 0, sizeof(*attr));
pos = wpabuf_head(msg);
@@ -622,7 +624,9 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
if (wps_set_attr(attr, type, pos, len) < 0)
return -1;
+#ifdef WPS_WORKAROUNDS
prev_type = type;
+#endif /* WPS_WORKAROUNDS */
pos += len;
}
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 5d0508c..505837b 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -22,7 +22,6 @@
#include "crypto/sha256.h"
#include "crypto/random.h"
#include "wps_i.h"
-#include "wps_dev_attr.h"
void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 5b3c045..0fbaa3f 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -967,7 +967,7 @@ static enum wps_process_res wps_process_m4(struct wps_data *wps,
return WPS_CONTINUE;
}
- if (wps_validate_m4_encr(decrypted, attr->version2 != 0) < 0) {
+ if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) {
wpabuf_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
@@ -1020,7 +1020,7 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps,
return WPS_CONTINUE;
}
- if (wps_validate_m6_encr(decrypted, attr->version2 != 0) < 0) {
+ if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) {
wpabuf_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
@@ -1086,8 +1086,8 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps,
return WPS_CONTINUE;
}
- if (wps_validate_m8_encr(decrypted, wps->wps->ap, attr->version2 != 0)
- < 0) {
+ if (wps_validate_m8_encr(decrypted, wps->wps->ap,
+ attr->version2 != NULL) < 0) {
wpabuf_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index a461836..856e9fb 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -502,16 +502,61 @@ static void wps_er_get_device_info(struct wps_er_ap *ap)
}
+static const char * wps_er_find_wfadevice(const char *data)
+{
+ const char *tag, *tagname, *end;
+ char *val;
+ int found = 0;
+
+ while (!found) {
+ /* Find next <device> */
+ for (;;) {
+ if (xml_next_tag(data, &tag, &tagname, &end))
+ return NULL;
+ data = end;
+ if (!os_strncasecmp(tagname, "device", 6) &&
+ *tag != '/' &&
+ (tagname[6] == '>' || !isgraph(tagname[6]))) {
+ break;
+ }
+ }
+
+ /* Check whether deviceType is WFADevice */
+ val = xml_get_first_item(data, "deviceType");
+ if (val == NULL)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val);
+ found = os_strcasecmp(val, "urn:schemas-wifialliance-org:"
+ "device:WFADevice:1") == 0;
+ os_free(val);
+ }
+
+ return data;
+}
+
+
static void wps_er_parse_device_description(struct wps_er_ap *ap,
struct wpabuf *reply)
{
/* Note: reply includes null termination after the buffer data */
- const char *data = wpabuf_head(reply);
+ const char *tmp, *data = wpabuf_head(reply);
char *pos;
wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
wpabuf_head(reply), wpabuf_len(reply));
+ /*
+ * The root device description may include multiple devices, so first
+ * find the beginning of the WFADevice description to allow the
+ * simplistic parser to pick the correct entries.
+ */
+ tmp = wps_er_find_wfadevice(data);
+ if (tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - "
+ "trying to parse invalid data");
+ } else
+ data = tmp;
+
ap->friendly_name = xml_get_first_item(data, "friendlyName");
wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 65ff40d..eda1c70 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -310,13 +310,17 @@ static void wps_registrar_add_pbc_session(struct wps_registrar *reg,
static void wps_registrar_remove_pbc_session(struct wps_registrar *reg,
- const u8 *uuid_e)
+ const u8 *uuid_e,
+ const u8 *p2p_dev_addr)
{
struct wps_pbc_session *pbc, *prev = NULL, *tmp;
pbc = reg->pbc_sessions;
while (pbc) {
- if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) {
+ if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 ||
+ (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) &&
+ os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
+ 0)) {
if (prev)
prev->next = pbc->next;
else
@@ -485,10 +489,8 @@ static void wps_set_pushbutton(u16 *methods, u16 conf_methods)
*methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
if (conf_methods & WPS_CONFIG_PHY_PUSHBUTTON)
*methods |= WPS_CONFIG_PHY_PUSHBUTTON;
- if ((*methods & WPS_CONFIG_VIRT_PUSHBUTTON) !=
- WPS_CONFIG_VIRT_PUSHBUTTON ||
- (*methods & WPS_CONFIG_PHY_PUSHBUTTON) !=
- WPS_CONFIG_PHY_PUSHBUTTON) {
+ if (!(*methods & (WPS_CONFIG_VIRT_PUSHBUTTON |
+ WPS_CONFIG_PHY_PUSHBUTTON))) {
/*
* Required to include virtual/physical flag, but we were not
* configured with push button type, so have to default to one
@@ -549,15 +551,7 @@ static int wps_build_probe_config_methods(struct wps_registrar *reg,
static int wps_build_config_methods_r(struct wps_registrar *reg,
struct wpabuf *msg)
{
- u16 methods;
- methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
- methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
- WPS_CONFIG_PHY_PUSHBUTTON);
-#endif /* CONFIG_WPS2 */
- if (reg->pbc)
- wps_set_pushbutton(&methods, reg->wps->config_methods);
- return wps_build_config_methods(msg, methods);
+ return wps_build_config_methods(msg, reg->wps->config_methods);
}
@@ -901,8 +895,8 @@ static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx)
* PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout
* or when a PBC registration is completed. If more than one Enrollee in active
* PBC mode has been detected during the monitor time (previous 2 minutes), the
- * PBC mode is not actived and -2 is returned to indicate session overlap. This
- * is skipped if a specific Enrollee is selected.
+ * PBC mode is not activated and -2 is returned to indicate session overlap.
+ * This is skipped if a specific Enrollee is selected.
*/
int wps_registrar_button_pushed(struct wps_registrar *reg,
const u8 *p2p_dev_addr)
@@ -951,6 +945,18 @@ static void wps_registrar_pin_completed(struct wps_registrar *reg)
}
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e)
+{
+ if (registrar->pbc) {
+ wps_registrar_remove_pbc_session(registrar,
+ uuid_e, NULL);
+ wps_registrar_pbc_completed(registrar);
+ } else {
+ wps_registrar_pin_completed(registrar);
+ }
+}
+
+
int wps_registrar_wps_cancel(struct wps_registrar *reg)
{
if (reg->pbc) {
@@ -1420,6 +1426,25 @@ static int wps_build_credential(struct wpabuf *msg,
}
+int wps_build_credential_wrap(struct wpabuf *msg,
+ const struct wps_credential *cred)
+{
+ struct wpabuf *wbuf;
+ wbuf = wpabuf_alloc(200);
+ if (wbuf == NULL)
+ return -1;
+ if (wps_build_credential(wbuf, cred)) {
+ wpabuf_free(wbuf);
+ return -1;
+ }
+ wpabuf_put_be16(msg, ATTR_CRED);
+ wpabuf_put_be16(msg, wpabuf_len(wbuf));
+ wpabuf_put_buf(msg, wbuf);
+ wpabuf_free(wbuf);
+ return 0;
+}
+
+
int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
{
struct wpabuf *cred;
@@ -1593,6 +1618,35 @@ static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg)
}
+static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
+{
+ struct wpabuf *msg, *plain;
+
+ msg = wpabuf_alloc(1000);
+ if (msg == NULL)
+ return NULL;
+
+ plain = wpabuf_alloc(200);
+ if (plain == NULL) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+
+ if (wps_build_ap_settings(wps, plain)) {
+ wpabuf_free(plain);
+ wpabuf_free(msg);
+ return NULL;
+ }
+
+ wpabuf_put_be16(msg, ATTR_CRED);
+ wpabuf_put_be16(msg, wpabuf_len(plain));
+ wpabuf_put_buf(msg, plain);
+ wpabuf_free(plain);
+
+ return msg;
+}
+
+
static struct wpabuf * wps_build_m2(struct wps_data *wps)
{
struct wpabuf *msg;
@@ -2551,6 +2605,8 @@ static void wps_cred_update(struct wps_credential *dst,
static int wps_process_ap_settings_r(struct wps_data *wps,
struct wps_parse_attr *attr)
{
+ struct wpabuf *msg;
+
if (wps->wps->ap || wps->er)
return 0;
@@ -2577,12 +2633,24 @@ static int wps_process_ap_settings_r(struct wps_data *wps,
*/
wps_registrar_pin_completed(wps->wps->registrar);
+ msg = wps_build_ap_cred(wps);
+ if (msg == NULL)
+ return -1;
+ wps->cred.cred_attr = wpabuf_head(msg);
+ wps->cred.cred_attr_len = wpabuf_len(msg);
+
if (wps->ap_settings_cb) {
wps->ap_settings_cb(wps->ap_settings_cb_ctx,
&wps->cred);
+ wpabuf_free(msg);
return 1;
}
wps_sta_cred_cb(wps);
+
+ wps->cred.cred_attr = NULL;
+ wps->cred.cred_attr_len = 0;
+ wpabuf_free(msg);
+
return 1;
}
}
@@ -2983,7 +3051,8 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
if (wps->pbc) {
wps_registrar_remove_pbc_session(wps->wps->registrar,
- wps->uuid_e);
+ wps->uuid_e,
+ wps->p2p_dev_addr);
wps_registrar_pbc_completed(wps->wps->registrar);
} else {
wps_registrar_pin_completed(wps->wps->registrar);
diff --git a/src/wps/wps_ufd.c b/src/wps/wps_ufd.c
index 1a911e1..61f6553 100644
--- a/src/wps/wps_ufd.c
+++ b/src/wps/wps_ufd.c
@@ -16,7 +16,6 @@
#include "common.h"
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/wait.h>
#include <fcntl.h>
#include <dirent.h>
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 763dcaf..06dcd20 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -47,7 +47,7 @@
* -- Needs renaming with module prefix to avoid polluting the debugger
* namespace and causing possible collisions with other static fncs
* and structure declarations when using the debugger.
- * -- The http error code generation is pretty bogus, hopefully noone cares.
+ * -- The http error code generation is pretty bogus, hopefully no one cares.
*
* Author: Ted Merrill, Atheros Communications, based upon earlier work
* as explained above and below.
@@ -172,7 +172,7 @@
#include "includes.h"
-#include <assert.h>
+#include <time.h>
#include <net/if.h>
#include <netdb.h>
#include <sys/ioctl.h>
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index c7fb158..4c4aebf 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -97,16 +97,6 @@ static int line_length(const char *l)
}
-/* No. of chars excluding trailing whitespace */
-static int line_length_stripped(const char *l)
-{
- const char *lp = l + line_length(l);
- while (lp > l && !isgraph(lp[-1]))
- lp--;
- return lp - l;
-}
-
-
static int str_starts(const char *str, const char *start)
{
return os_strncmp(str, start, os_strlen(start)) == 0;
@@ -530,7 +520,6 @@ static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
#ifndef CONFIG_NO_STDOUT_DEBUG
const char *start = data;
#endif /* CONFIG_NO_STDOUT_DEBUG */
- const char *end;
int got_host = 0;
int got_st = 0, st_match = 0;
int got_man = 0;
@@ -545,7 +534,6 @@ static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
/* Parse remaining lines */
for (; *data != '\0'; data += line_length(data)) {
- end = data + line_length_stripped(data);
if (token_eq(data, "host")) {
/* The host line indicates who the packet
* is addressed to... but do we really care?
diff --git a/src/wps/wps_upnp_web.c b/src/wps/wps_upnp_web.c
index 917f60b..ce0bede 100644
--- a/src/wps/wps_upnp_web.c
+++ b/src/wps/wps_upnp_web.c
@@ -956,7 +956,7 @@ static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
break; /* no unterminated lines allowed */
/* NT assures that it is our type of subscription;
- * not used for a renewl.
+ * not used for a renewal.
**/
match = "NT:";
match_len = os_strlen(match);